Await在for循环中的使用

Posted by Turingdo Studio on November 4, 2020

await 在for循环中的使用。

以前await必须与 async配对使用。 现在 Chrome 86已经支持,直接在for循环中单独使用await了。

for(let i=0; i< 3;i++){
const result = await i+1;

console.log(result)
}

await与 for of

for await (let num of [1,2,3]) {
  console.log(num);// 1,2,3
}

await 在forEach,map, reduce循环中不起作用

forEach、map、reduce和promise那点事

const fetch = (forceTrue) =>
  new Promise((resolve, reject) => {
    if (Math.random() > 0.2 || forceTrue) {
      resolve("success");
    } else {
      reject("error");
    }
  });

const result = [];

[0, 1, 2].forEach(async () => {
  const value = await fetch(true);
  result.push(value);
});

console.log(result); // 返回 []

forEach愿源码实现中通过 while 循环里面多次调用callback.call(T, kValue, k, O);来实现的, 由于它前面没有 await, 所以每次循环执行到这里的时候并没有等待它执行完,最后打印 result 的时候就是空数组了。

解决方法

可以通过在最外层加一层自执行的async 函数 fix:

(async function(){
 await [0, 1, 2].forEach(async () => {
  const value = await fetch(true);
  result.push(value);
});
})()

实现多个 promise 同步执行,不管有没有抛出错误,都把结果收集起来

  • 使用 for 循环解决
Promise.myAll = function (promiseArr) {
    const len = promiseArr.length;
    const result = [];
    let count = 0;

    return new Promise((resolve, reject) => {
        for (let i = 0; i < len; ++i) {
            promiseArr[i].then((res) => {
                result[i] = res;
                ++count;

                if (count >= len) {
                    resolve(result);
                }
            }, (err) => {
                result[i] = err;
                ++count;

                if (count >= len) {
                    resolve(result);
                }
            });
        }
    });
}

// test
const fetch = (forceTrue) => new Promise((resolve, reject) => {
    if (Math.random() > 0.2 || forceTrue) {
        resolve('success');
    } else {
        reject('error');
    }
});

Promise.myAll([fetch(), fetch(), fetch()])
    .then(res => console.log(res));  // ["success", "success", "error"]

Hack

如果注意到 promise 的「then 方法和 catch 方法都会返回一个 promise」的话,就可以用下面的简单方法:

Promise.myAll = function (promiseArr) {
    // 就这一行代码!
    return Promise.all(promiseArr.map(item => item.catch(err => err)));
}

// test
const fetch = (forceTrue) => new Promise((resolve, reject) => {
    if (Math.random() > 0.2 || forceTrue) {
        resolve('success');
    } else {
        reject('error');
    }
});

Promise.myAll([fetch(), fetch(), fetch()])
    .then(res => console.log(res)); // ["error", "error", "success"]