await在forEach中无效

·  阅读 2246

场景

现有一个数组,要依次循环去请求拿到结果。
想当然你可能会写出来下面的代码

错误示例

  function api(i) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                const n = Math.random();
                if (n > 0.5) {
                    resolve(n);
                } else {
                    resolve(-n)
                }
            }, 1000 * 1);
        });
    }
    const list = [1, 2, 3, 4, 5];
    async function fn() {
        // 数组forEach遍历方法 await无效
        list.forEach(async (el, index) => {
            const n = await api(index);
            console.log(n, index);
        });
    };
    fn();
复制代码

通过控制台发现,代码并没有按照预期依次打印出来,而是等待一下,全部打印出来。再次查看代码,确认语法没错。问题就很明显了,出在forEach。       

正确代码

function api(i) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                const n = Math.random();
                if (n > 0.5) {
                    resolve(n);
                } else {
                    resolve(-n)
                }
            }, 1000 * 1);
        });
    }
    const list = [1, 2, 3, 4, 5];

    async function fn() {
        for (let i = 0; i < list.length; i++) {
            const n = await api(i);
            console.log('for--------', n, i);
        }
    };
    fn();
复制代码

polyfill

forEach() 是在第五版本里被添加到 ECMA-262 标准的;这样它可能在标准的其他实现中不存在,你可以在你调用 forEach() 之前插入下面的代码,在本地不支持的情况下使用 forEach()。该算法是 ECMA-262 第5版中指定的算法。它假定 Object 和 TypeError 拥有它们的初始值,且 callback.call 等价于 Function.prototype.call()

// Production steps of ECMA-262, Edition 5, 15.4.4.18
// Reference: http://es5.github.io/#x15.4.4.18
if (!Array.prototype.forEach) {

  Array.prototype.forEach = function(callback, thisArg) {

    var T, k;

    if (this == null) {
      throw new TypeError(' this is null or not defined');
    }

    // 1. Let O be the result of calling toObject() passing the
    // |this| value as the argument.
    var O = Object(this);

    // 2. Let lenValue be the result of calling the Get() internal
    // method of O with the argument "length".
    // 3. Let len be toUint32(lenValue).
    var len = O.length >>> 0;

    // 4. If isCallable(callback) is false, throw a TypeError exception.
    // See: http://es5.github.com/#x9.11
    if (typeof callback !== "function") {
      throw new TypeError(callback + ' is not a function');
    }

    // 5. If thisArg was supplied, let T be thisArg; else let
    // T be undefined.
    if (arguments.length > 1) {
      T = thisArg;
    }

    // 6. Let k be 0
    k = 0;

    // 7. Repeat, while k < len
    while (k < len) {

      var kValue;

      // a. Let Pk be ToString(k).
      //    This is implicit for LHS operands of the in operator
      // b. Let kPresent be the result of calling the HasProperty
      //    internal method of O with argument Pk.
      //    This step can be combined with c
      // c. If kPresent is true, then
      if (k in O) {

        // i. Let kValue be the result of calling the Get internal
        // method of O with argument Pk.
        kValue = O[k];

        // ii. Call the Call internal method of callback with T as
        // the this value and argument list containing kValue, k, and O.
        callback.call(T, kValue, k, O);
      }
      // d. Increase k by 1.
      k++;
    }
    // 8. return undefined
  };
}

复制代码

总结

await要写在async函数里面,await只是语法糖,使异步变成同步,便于书写和阅读。await 等待异步的promise函数执行完成resolve或者reject,抛异常使用try catch。forEach使用await无效,改用for循环。

分类:
前端
标签:
分类:
前端
标签: