异步/等待内部箭头函数(Array # map/filter)

我在这段代码中得到了编译时错误:

const someFunction = async (myArray) => {
return myArray.map(myValue => {
return {
id: "my_id",
myValue: await service.getByValue(myValue);
}
});
};

错误信息是:

“等待”是一个保留字

为什么我不能这样使用它?

73115 次浏览

这是因为 map中的函数不是 异步,所以不能在它的 return 语句中使用 等待。它通过以下修改进行编译:

const someFunction = async (myArray) => {
return myArray.map(async (myValue) => { // <-- note the `async` on this line
return {
id: "my_id",
myValue: await service.getByValue(myValue)
}
});
};

试试 Babel REPL

因此,在没有看到应用程序的其余部分的情况下是不可能给出推荐的,但这取决于您想要做什么,要么使 内心功能异步,要么尝试为这个块提出一些不同的架构。

更新: 我们可能会得到顶级等待一天: https://github.com/MylesBorins/proposal-top-level-await

您不能像您想象的那样执行此操作,因为如果 await不直接位于 async函数中,则无法使用它。

这里明智的做法是将函数异步传递给 map。这意味着 map将返回一个承诺数组。然后,当所有的承诺返回时,我们可以使用 Promise.all来获得结果。因为 Promise.all本身返回一个承诺,所以外部函数不需要是 async

const someFunction = (myArray) => {
const promises = myArray.map(async (myValue) => {
return {
id: "my_id",
myValue: await service.getByValue(myValue)
}
});
return Promise.all(promises);
}

如果要使用异步映射函数运行 map,可以使用以下代码:

const resultArray = await Promise.all(inputArray.map(async (i) => someAsyncFunction(i)));

工作原理:

  • inputArray.map(async ...)返回一个承诺数组——对于 inputArray中的每个值,返回一个承诺数组。
  • Promise.all()放在一系列承诺周围,可以将其转换为单个承诺。
  • 来自 Promise.all()的单个承诺返回一个值数组——单个承诺每个解析为一个值。
  • 我们将 await放在 Promise.all()的前面,这样我们等待合并的承诺解析并将解析的子承诺数组存储到变量 resultArray中。

最后,我们在 resultArray中为 inputArray中的每个项目得到一个输出值,通过函数 someAsyncFunction进行映射。我们必须等待所有异步函数解析后才能得到结果。

它将是2个指令,但只是移动“等待”与额外的指令

let results = array.map((e) => fetch('....'))
results  = await Promise.all(results)

我尝试了所有这些答案,但是没有一个适合我的情况,因为所有的答案都返回一个 promise对象,而不是像这样返回一个 result of the promise对象:

{
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: Array(3)
0: ...an object data here...
1: ...an object data here...
2: ...an object data here...
length: 3
[[Prototype]]: Array(0)
}

然后我找到了这个答案 https://stackoverflow.com/a/64978715/8339172,它指出 map函数是否不是异步的或者承诺感知的。 因此,我没有在 map函数中使用 await,而是使用 for循环和 await单独的项目,因为他说 for循环是 async感知的,会暂停循环。

如果希望在转移到下一个值之前解析每个重新映射的值,可以将数组作为异步迭代进行处理。

下面,我们使用库 ITER-OPS,将每个值重新映射到承诺,然后生成一个具有解析值的对象,因为 map本身不应该在内部处理任何承诺。

import {pipe, map, wait, toAsync} from 'iter-ops';


const i = pipe(
toAsync(myArray), // make asynchronous
map(myValue => {
return service.getByValue(myValue).then(a => ({id: 'my_id', myValue: a}))
}),
wait() // wait for each promise
);


(async function() {
for await (const a of i) {
console.log(a); // print resulting objects
}
})

在每个值之后,我们使用 等等在生成每个重新映射的值时解析它们,以保持解析要求与原始问题一致。