Async/Await 里面 Array#map()

Async/Await inside Array#map()

我遇到此代码的编译时错误:

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

错误信息是:

await is a reserved word

为什么我不能这样用?

我也试过另一种方法,但它给了我同样的错误:

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

那是因为 map 中的函数不是 async,所以你不能在它的 await =28=]语句。它使用此修改进行编译:

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

Try it out in Babel REPL

所以……如果不查看您的应用程序的其余部分就无法给出推荐,但取决于您要做什么,可以使 inner 函数异步或尝试为这个区块想出一些不同的架构。

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

你不能像你想象的那样做,因为你不能使用await如果它不直接在async函数中。

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

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

如果你想运行使用异步映射函数映射你可以使用下面的代码:

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

工作原理:

  • inputArray.map(async ...) returns 一组承诺 - inputArray 中的每个值一个。
  • Promise.all() 放在 promise 数组周围会将其转换为单个 promise。
  • 来自 Promise.all() returns 一组值的单个承诺 - 每个承诺都解析为一个值。
  • 我们将 await 放在 Promise.all() 前面,这样我们就可以等待合并的 promise 解析并将已解析的子 promises 数组存储到变量 resultArray 中。

最终我们在inputArray中的每一项得到一个resultArray中的输出值,通过函数someAsyncFunction映射。在结果可用之前,我们必须等待所有异步函数解决。

这将是 2 条指令,但只需将“await”移至额外的指令

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

我尝试了所有这些答案,但没有人适合我的情况,因为所有答案 return 一个 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)
}

然后我找到了这个答案 ,它指出 map 函数是否不异步或承诺感知。 因此,我没有在 map 函数中使用 await,而是使用 for 循环和 await 单个项目,因为他说 for 循环是 async意识到并将暂停循环。

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

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

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
    }
})

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