forEach와 await/async의 문제

2510 단어
최근에 node로 정적 파일 서버를 쓸 때 문제가 발생했습니다. forEach 순환에서await/async 비동기 함수를 호출하는 문제입니다.이 문제도 몇 번 만났으니 다음에 잊지 않도록 여기에 적어 두어라.

문제가 재현되다

var getNumbers = () => {
  return Promise.resolve([1, 2, 3])
}

var multi = num => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (num) {
        resolve(num * num)
      } else {
        reject(new Error('num not specified'))
      }
    }, 1000)
  })
}

async function test () {
  var nums = await getNumbers()
  nums.forEach(async x => {
    var res = await multi(x)
    console.log(res)
  })
}

test()

테스트 함수가 실행된 후에 내가 기대하는 결과는 코드가 직렬로 실행된 것이다. 나는 1초마다 하나의 수를 출력할 것이다.일...사...9, 그런데 지금 얻은 결과는 1초를 기다려서 같이 출력한 결과입니다. 149.

문제를 찾다


왜 for 순환/for...of 안에서await/async의 기능을 실현할 수 있지만forEach에서는 안 되나요?일단 MDN 사이트의 Polyfill을 살펴보도록 하겠습니다.
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');
    }

    var O = Object(this);
    var len = O.length >>> 0;

    if (typeof callback !== "function") {
      throw new TypeError(callback + ' is not a function');
    }

    if (arguments.length > 1) {
      T = thisArg;
    }
    k = 0;

    while (k < len) {
      var kValue;
      if (k in O) {
        kValue = O[k];
        callback.call(T, kValue, k, O);
      }
      k++;
    }
  };
}

우리가 forEach에 쓴callback 함수는 while 순환에서 직접 호출되어 간소화되는 것을 볼 수 있다
Array.prototype.forEach = function (callback) {
  // this represents our array
  for (let index = 0; index < this.length; index++) {
    // We call the callback for each entry
    callback(this[index], index, this)
  }
}

for 순환에서 비동기 함수를 실행한 셈
async function test () {
  var nums = await getNumbers()
//   nums.forEach(async x => {
//     var res = await multi(x)
//     console.log(res)
//   })
  for(let index = 0; index < nums.length; index++) {
    (async x => {
      var res = await multi(x)
      console.log(res)
    })(nums[index])
  }
}

해결 방법


for로...forEach 대신 of 또는 for 순환
async function test () {
  var nums = await getNumbers()
  for(let x of nums) {
    var res = await multi(x)
    console.log(res)
  }
}

다음으로 전송:https://www.cnblogs.com/chrissong/p/11247827.html

좋은 웹페이지 즐겨찾기