为什么这个简单的异步-承诺-减少代码有效?

时间:2019-06-27 11:07:20

标签: javascript promise async-await reduce

为什么此代码可以完美运行?我不知道为什么此代码有效。

循环方法不返回任何内容,因此累加器必须为null,并且此代码不能正常工作。

const arr = [1, 2, 3, 4];

  const awaitFunc = (val) => new Promise(function (resolve, reject) {
    setTimeout(function () {
      console.log('awaitFunc', val);
	  resolve();
	}, 500);
  });
  
  const start = async () => {
    console.log('start');

    await arr.reduce(async (promise, val, index) => {
      await promise;

      console.log('reduce loop', val);
      
      await awaitFunc(val);
    }, Promise.resolve());

    console.log('end');
  };

  start();

结果似乎是这样。

start
reduce loop 1
(500ms)
awaitFunc 1
reduce loop 2
(500ms)
awaitFunc 2
reduce loop 3
(500ms)
awaitFunc 3
reduce loop 4
(500ms)
awaitFunc 4
end

1 个答案:

答案 0 :(得分:1)

一个async函数会自动返回一个Promise。如果函数包含await,则所有await完成后,Promise便会解析(并且解释器到达功能块的底部)。由于累加器是async函数,它会自动返回一个Promise,因此await会计算 last 迭代(累加器的最后一次运行)返回的Promise的分辨率。有道理。

所以

 await arr.reduce(async (promise, val, index) => {
   await promise;

   console.log('reduce loop', val);

   await awaitFunc(val);
 }, Promise.resolve());

等同于

await arr.reduce((promise, val, index) => {
  return promise.then(() => {
    console.log('reduce loop', val);
    return awaitFunc(val);
    // ^^^^^^^ returned end of Promise chain, so accumulator promise in next reduce loop will resolve
    // once above promise resolves
  });
}, Promise.resolve());

 await arr.reduce((promise, val, index) => {
   // just for illustration, don't use the explicit Promise construction antipattern
   return new Promise((resolve) => {
     // await promise;
     promise.then(() => {
       console.log('reduce loop', val);
       // await awaitFunc(val);
       awaitFunc(val).then(resolve)
       //                  ^^^^^^^ Accumulator promise in next reduce loop will resolve
     });
   });
 }, Promise.resolve());

const arr = [1, 2, 3, 4];

const awaitFunc = (val) => new Promise(function (resolve, reject) {
  setTimeout(function () {
    console.log('awaitFunc', val);
    resolve();
  }, 500);
});

const start = async () => {
  console.log('start');

   await arr.reduce((promise, val, index) => {
     // just for illustration, don't use the explicit Promise construction antipattern
     return new Promise((resolve) => {
       // await promise;
       promise.then(() => {
         console.log('reduce loop', val);
         // await awaitFunc(val);
         awaitFunc(val).then(resolve)
       });
     });
   }, Promise.resolve());

  console.log('end');
};

start();