JavaScript串行承诺与Settimeout一起



我正在努力建立带有SettieTimeout的Promise Chain。所有的承诺都需要以串联而不平行的方式运行。我正在使用蓝鸟模块实现承诺执行的串行流。

有人可以向我解释为什么此代码为我提供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) {
    });

有几个问题:

  • 您所拥有的console.log并非取决于先前的解决承诺。只有超时确定 将发生输出。当您在"同一"时间创建所有四个诺言时,同时调用了所有四个setTimeout调用,他们的回调将在确定的超时时访问。链条之后您的链条承诺无关紧要...要解决此问题,您需要在then回调中移动console.log,因为该回调只有在解决链条中的先前承诺时才能执行。

    <</p> <。
  • 在您的代码中未调用resolve功能。您需要添加括号。

  • setTimeout回调的分辨率参数隐藏了 real> real 函数,具有相同名称:您需要删除该参数。

这是建议的校正。对于此片段,我已经用标准Array#reduce替换了蓝鸟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());

如果您具有Promist-Creator函数p,并且您想在serial 中运行一系列Promises ,则无需您加载一个数组有了承诺 - 而是让它成为正常的值

请注意,我也不在这里使用value * 1000 - 在您的代码中,您认为您必须使用计算的Settimeout延迟来人为地编排以特定顺序发射的承诺;事实并非如此。仔细观察以下代码的评估,以了解我们如何在每个诺言和.then之间有1秒的延迟使事情保持顺序

还要注意,该代码将在第一个承诺解决之后立即开始输出 - 而不是等待所有承诺在输出所有值之前解决的所有承诺

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())

好,所以您有这些承诺按顺序运行,但是为什么呢?除非以后的步骤以某种方式取决于早期步骤的结果,否则您没有理由要减慢这些速度 - 即,每个诺言的结果不依赖其他结果,因此只需尽可能快地计算它们即可。但是您担心订单会丢失,对吗?不用担心,一切都会好起来的 - 我什至会使用随机延迟向您展示每个诺言都不重要的时间

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不同。所有承诺都等待所有承诺在您可用的任何值之前完成的所有承诺(。

我仅作为替代方案而提到这一点,因为您提供的示例不显示真正的需要 serial执行的承诺。您可能已经天真地简化了问题的域名,但只有您是否知道情况。

最新更新