【问题标题】:Make dynamically created promises execute in sequence让动态创建的 Promise 按顺序执行
【发布时间】:2018-09-16 01:55:06
【问题描述】:

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

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

 executeAllPromisesSequentially(promiseArray)

在哪里

executeAllPromisesSequentially is functionally equivalent to

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

【问题讨论】:

  • 是的,你可以通过链接你在循环中创建的承诺来做到这一点.......push(promise = promise.then(() => createNewPromise(x))) - 当然,你需要一个初始值 promise 来启动链......比如说Promsie.resolve() 例如......如果你想访问解析的值,它会变得有点复杂
  • 所有的promise都只有副作用还是你想知道它们的resolve值?
  • 让它们按顺序执行?您的意思是按顺序解决它们?因为promise 将在它创建的那一刻被执行。
  • 如果它符合您的要求,请检查此stackoverflow.com/questions/49606387/…

标签: javascript node.js promise es6-promise


【解决方案1】:

我的gist上显示了一些模式

使用 Reduce 进行 Promise 迭代

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;
}

【讨论】:

    【解决方案2】:

    就像 jaromandaX 所说的那样建立一个链。但是,您需要确保在循环内使用 let 来关闭 x:

      let chain = Promise.resolve();
      const promises = [];
    
      for(let x = 0; x < maxValue; x++)
        promises.push(chain = chain.then(() => createNewPromise(x)));
    

    【讨论】:

      【解决方案3】:

      减少或循环/递归链接是一种常见的做法,但是如果您想保留和访问此处的中间分辨率,我还有另一种方法,即在 JS 中使用 Haskell 的 scanl 函数的发明。

      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,我们可以尝试通过将中间分辨率保存在结果数组中来对promise 进行排序。

      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)));
      .as-console-wrapper {
      max-height : 100% !important
      }

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-07
        • 2020-03-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多