使用 ES6 promises 的顺序迭代

Sequential iteration using ES6 promises

我期待下面的 node.js 代码将按以下顺序打印输出

1000
2000
3000
4000
"All tasks completed"

而是按下面提到的顺序打印

"All tasks completed"
1000
2000
3000
4000

代码

'use strict';

var tasks = [1000, 2000, 3000, 4000];
var promise = Promise.resolve();


function test() {
  tasks.forEach(function(task) {
    promise = promise.then(function() {
      setTimeout(function() {
        console.log(task);
      }, task);
    });
  });
}

test();

promise.then(function() {
  console.log('All tasks completed');
});

需要修改什么,以便"All tasks completed"最后打印。

  1. 我的示例使用 ES6 promises 而不是 bluebird 。
  2. 此外,我不是在问关于 promises 的一般性问题,而是关于一个具体的例子。

在所有 then 函数中,您没有 returning 任何东西,而是触发异步操作。因此,promise 链与异步操作无关。这就是为什么您无法按照自己的意愿控制流量。

你可以做的是,return 来自每个 then 处理程序的 Promise,只有在异步操作完成时才会解决,就像这样

  tasks.forEach(function(task) {
    promise = promise.then(function() {
      return new Promise((resolve, reject) => {
        setTimeout(function() {
          console.log(task);
          resolve();
        }, task);
      })
    });
  });

记住,这将一个接一个地触发异步操作。例如,一秒钟后,它将打印 1000,然后将启动第二个异步操作,等待两秒钟,然后打印 2000,依此类推。基本上,您的程序将在大约 10 秒(1 + 2 + 3 + 4 秒)后退出,因为我们正在按顺序执行所有异步函数。


但是如果你想让它们全部同时触发,那么使用Promise.all,像这样

'use strict';

var tasks = [1000, 2000, 3000, 4000];

function test() {
  return Promise.all(tasks.map(function(task) {
    return new Promise((resolve, reject) => {
      setTimeout(function() {
        console.log(task);
        resolve();
      }, task);
    })
  }));
}

test().then(function() {
  console.log('All tasks completed');
});

现在,所有的异步函数都是一次性触发的,所以一秒后打印1000,两秒后打印2000等等。您的程序将在 4 秒后完成所有异步操作,因为它们都是立即启动的。

目前,这是我想出的以顺序和阻塞方式迭代 promise 数组的唯一方法...

请检查代码示例...

const list = [1,2,3,4,5];

数字越大,承诺得到解决的速度就越快

const functionWithPromise = item => { 
  return new Promise((resolve) =>{
    setTimeout(resolve, 6000 - (1000 * item ) , item);
})}

Promise.all returns 一个包含 promises 的数组

const getData = async () => Promise.all(await iterateSequentiallyPromiseArray(list,functionWithPromise));

for 循环是唯一以阻塞方式迭代的循环

const iterateSequentiallyPromiseArray = async (array, fn) => {
    try {
      const results = [];
      for (let i = 0; i < array.length; i++) { 
        console.log('Start with index: ', i);
        const r = await fn(array[i]);
        console.log('in promise iteration', r);
        results.push(r);
      }
      return results; // will be resolved value of promise
    } catch (err) {
      console.log('_processArray');
      throw err;
    }

};

启动链

getData().then(console.log);