使动态创建的promises按顺序执行

时间:2018-04-06 05:30:35

标签: javascript node.js promise es6-promise

如何动态创建一系列promise并让它们按顺序执行?

pseudocode
 for x=0 to maxValue
   promiseArray.push(createNewPromise(x))

 executeAllPromisesSequentially(promiseArray)

,其中

executeAllPromisesSequentially is functionally equivalent to

promise1()
.then(promise2)
.then(promise3)
etc
...

3 个答案:

答案 0 :(得分:2)

我的gist

上显示了一些模式

使用Reduce

保证迭代
let tasks = [ /* ... */ ]
let promise = tasks.reduce((prev, task) => {
  return prev.then(() => {
    return task();
  });
}, Promise.resolve());
promise.then(() => {
//All tasks completed
});

顺序迭代模式

let tasks = [ /* ... */ ]
let promise = Promise.resolve();
tasks.forEach(task => {
  promise = promise.then(() => {
    return task();
  });
});
promise.then(() => {
//All tasks completed
});

顺序迭代示例

function spiderLinks(currentUrl, body, nesting) {
  let promise = Promise.resolve();
  if(nesting === 0) {
    return promise;
  }
  const links = utilities.getPageLinks(currentUrl, body);
  links.forEach(link => {
    promise = promise.then(() => spider(link, nesting - 1));
  });
  return promise;
}

答案 1 :(得分:1)

只需建立一个链,因为 jaromandaX 说。但是,您需要确保在循环内使用let来关闭x:

  let chain = Promise.resolve();
  const promises = [];

  for(let x = 0; x < maxValue; x++)
    promises.push(chain = chain.then(() => createNewPromise(x)));

答案 2 :(得分:0)

作为一种常见的做法,可以想到减少或循环/递归链接,但是如果你想在这里保留和访问中间分辨率,我可以通过使用Haskell scanl函数的发明来实现另一种方法在JS。

scanl与JS .reduce()类似,但与.map()类似,始终返回包含临时值的相同大小的数组。所以scanl函数看起来像;

var scanl = (xs, f, acc) => xs.map((a => e => a = f(a,e))(acc));

所以,如果你这样做;

scanl([1,2,3,4], (a,e) => a + e, 0) // -> [1,3,6,10]

因此现在手头有scanl我们可能会尝试通过将中间分辨率保存在结果数组中来对承诺进行排序。

&#13;
&#13;
var scanl = (xs, f, acc) => xs.map((a => e => a = f(a,e))(acc)),
    proms = Array(5).fill().map((_,i) => new Promise((v,x) => setTimeout(v,100+Math.random()*1900,`res ${i+1}`)));
  
proms = scanl(proms, (a,p,t) => a.then(v => (t = v, p))
                                 .then(v => `${t} and ${v}`)
                                 .then(s => (console.log(`did stg with ${s}`),s)), Promise.resolve("init 0"));
Promise.all(proms)
       .then(vs => vs.forEach(v => console.log(v)));
&#13;
.as-console-wrapper {
max-height : 100% !important
}
&#13;
&#13;
&#13;

当然上面的功能只是临时搭建。我使用未使用的t参数作为回调上下文中定义的临时变量。