【问题标题】:JavaScript Serial Promises with setTimeout带有 setTimeout 的 JavaScript 串行承诺
【发布时间】:2017-10-04 19:37:47
【问题描述】:

我正在构建带有 setTimeouts 的 Promise 链。所有的 Promise 都需要串联而不是并行运行。我正在使用 Bluebird 模块来实现 Promise 执行的串行流。

谁能解释一下为什么这段代码给我的输出是 1,2,3,4 而不是 4,3,2,1?

var bluebirdPromise = require('bluebird');

function p1(value) {
    return new Promise(function(resolve, reject) {
       setTimeout(function(resolve) {
           console.log(value);
           resolve;
       }, value * 1000);
    });
}

var arr = [p1(4), p1(3), p1(2), p1(1)];

bluebirdPromise.reduce(arr,
    function(item, index, length) {

    }).then(function (result) {

    });

【问题讨论】:

  • 当您调用p1 时,您已经开始操作。您的 arr 解决方案不起作用。

标签: javascript promise bluebird es6-promise


【解决方案1】:

如果您有一个 Promise-creator 函数 p,并且您想要串行运行一系列 Promise,则无需加载带有 Promise 的数组 - 相反,只需让它成为一个正常的值数组

请注意,我在这里也没有使用value * 1000 - 在您的代码中,您认为您必须使用计算的 setTimeout 延迟人为地编排按特定顺序触发的承诺;事实并非如此。仔细观察下面代码的评估,看看我们如何在每个 promise 之间有 1 秒的延迟,.then 保持秩序

另请注意,此代码将在第一个 Promise 解决后立即开始输出 - 而不是在输出所有值之前等待所有 Promise 解决

const p = x =>
  new Promise(f =>
    setTimeout(f, 1e3, x))
    
const arr = [4,3,2,1]

arr.reduce((acc, x) =>
  acc.then(() => p(x)).then(console.log), Promise.resolve())

好的,所以这些promise 是按顺序运行的,但是为什么呢?除非后面的步骤以某种方式依赖于前面步骤的结果,否则您没有理由要放慢这些速度——即,每个 Promise 的结果不依赖于其他的,所以尽可能快地计算它们。但是你担心订单会丢失,对吧?别担心,一切都会好起来的——我什至会使用随机延迟来告诉你每个承诺所花费的时间并不重要

const p = x =>
  new Promise(f =>
    setTimeout(f, 1e3 * Math.random(), x))
    
const arr = [4,3,2,1]

arr.map(p).reduce((acc, x) =>
  acc.then(() => x).then(console.log), Promise.resolve())

所以现在,所有的 Promise 都可以立即开始,一旦第一个 Promise 被解决,输出就会开始(不像 Promise.all 会等待所有的 Promise 完成,然后你才能使用任何值)。

我只提到这个作为替代方案,因为您提供的示例显示没有真正的 需要 承诺要串行执行。您可能天真地简化了问题的领域,但只有您自己知道是不是这样。

【讨论】:

    【解决方案2】:

    有几个问题:

    • 您拥有的console.log 不依赖于先前已解决的承诺。只有超时时间决定了输出何时发生。当您在“同一”时间创建所有四个 Promise,因此同时调用所有四个 setTimeout 调用时,它们的回调在确定的超时时被调用。之后如何链接承诺并不重要...要解决此问题,您需要将 console.log 移动到 then 回调中,因为该回调仅在链中的前一个承诺已解决时才会执行。

    • 您的代码中未调用resolve 函数。您需要添加括号。

    • setTimeout 回调的 resolve 参数隐藏了 real 同名函数:您需要删除该参数。

    这是建议的更正。对于这个 sn-p,我已将 bluebird reduce 替换为标准 Array#reduce,但它与 bluebird 的 reduce 类似:

    function p1(value) {
        return new Promise(function(resolve, reject) {
           setTimeout(function() { // ***
               resolve(value); // ***
           }, value * 1000);
        });
    }
    
    var arr = [p1(4), p1(3), p1(2), p1(1)];
    
    arr.reduce(function(promise, next) {
        return promise.then(_ => next).then( value => {
            console.log(value); // ***
            return value;
        });
    }, Promise.resolve());

    【讨论】:

      猜你喜欢
      • 2020-07-20
      • 1970-01-01
      • 1970-01-01
      • 2020-08-26
      • 1970-01-01
      • 1970-01-01
      • 2016-04-02
      • 2020-02-07
      • 2016-12-09
      相关资源
      最近更新 更多