地图函数中的异步等待未按顺序执行

时间:2021-02-02 23:48:41

标签: javascript async-await

我有以下代码:

var arr = [
    { condition: true, recursion: [], result: 'OLD_RESULT', recursiveArray: [{condition: true, result: 'OLD_RESULT'}] },
    {condition: false, result: 'OLD_RESULT'},
    { condition: true, recursion: [], result: 'OLD_RESULT', recursiveArray: [{condition: true, result: 'OLD_RESULT'}] },
    {condition: false, result: 'OLD_RESULT'},
];

var someAsyncCall = async () => {
    return 'NEW VALUE';
};

var asyncInMap = (arr) => {
    return arr.map(async (elem) => {
        const condition = elem.condition;
        if (condition) {
            const result = await someAsyncCall();
            elem.result = result;
        }
        if (elem.recursiveArray) {
            elem.recursion = asyncInMap(elem.recursiveArray);
        }
        console.log('SECOND:', elem);
        return elem;
    });
};

console.log('FIRST');
var promisesVal = asyncInMap(arr);
console.log('THIRD');
var completedVal = await Promise.all(promisesVal);
console.log('FOURTH', completedVal);

我的问题是按照我得到的 console.log's 的顺序:

FIRST
SECOND: {condition: false, result: "OLD_RESULT"}
SECOND: {condition: false, result: "OLD_RESULT"}
THIRD
SECOND: {condition: true, recursion: Array(1), result: "NEW VALUE", recursiveArray: Array(1)}
SECOND: {condition: true, recursion: Array(1), result: "NEW VALUE", recursiveArray: Array(1)}
SECOND: {condition: true, result: "NEW VALUE"}
SECOND: {condition: true, result: "NEW VALUE"}
FOURTH (4) [{…}, {…}, {…}, {…}]

为什么在所有 Third Second 完成之前打印 console.log 日志?这是因为我在 asyncInMap 函数中使用递归和 async/await 吗?理想情况下,asyncInMap 应该完成(首先打印所有 Second 日志)然后只有 Third 日志应该正确打印?

1 个答案:

答案 0 :(得分:3)

这是js中async await代码的特性。 THIRD 将比该调用中的任何异步操作更早地被调用,因为事件循环的工作方式与 js 中的一样。但是您的代码中存在一个错误,它可以使 FOURTH 在所有 SECOND 完成之前被记录,因为您没有等到递归 SECOND 在任何地方完成。要解决此问题,您可以在此处添加等待

elem.recursion = await Promise.all(asyncInMap(elem.recursiveArray));

此外,如果您想保持执行顺序,您可以进行简单的迭代并在函数顶层执行所有等待逻辑

var asyncInMap = async (arr) => {
     for(const elem of arr) {
       if(elem.condition) {
         elem.result = await someAsyncCall();
       }
       if(elem.recursiveArray) elem.recursion = await asyncInMap(elem.recursiveArray);
       console.log('SECOND:', elem);
     }
     return arr;
};



console.log('FIRST');
var promisesVal = asyncInMap(arr);
console.log('THIRD', 'calls can still be in progress here');
var completedVal = await promisesVal;
console.log('FOURTH', 'everything is completed here', completedVal);

请注意,在最后一个示例中,不会同时执行并行操作。它们将按照预定义的顺序一个一个地“异步调用”