按顺序执行promise

时间:2016-06-24 06:00:44

标签: javascript promise

此页面的示例。 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

var p1 = new Promise(function(resolve, reject){
    console.log('p1');
    setTimeout(resolve, 5000, "one");
});
var p2 = new Promise(function(resolve, reject){
    console.log('p2');
    setTimeout(resolve, 3000, "two");
});
var p3 = new Promise(function(resolve, reject){
    console.log('p3');
    setTimeout(resolve, 2000, "three");
});
var p4 = new Promise(function(resolve, reject){
    console.log('p4');
    setTimeout(resolve, 1000, "four");
});
var p5 = new Promise(function(resolve, reject){
    console.log('p5');
    setTimeout(resolve, 4000, "five");
});

Promise.all([p1, p2, p3, p4, p5]).then(function(value) {
    console.log(value);
}, function(reason) {
    console.log(reason)
});

输出

p1, p2, p3, p4, p5

所有p1-p5都会立即执行,但是我想说是否要对它进行排序。一旦p1结算,则应调用p2,然后调用p3。

我怎样才能序列/链(而不是并行)承诺而不是一次性迭代。

如果我在等待每个承诺时采用手动方法,那就会产生回调地狱。请指教。

4 个答案:

答案 0 :(得分:3)

首先,承诺可能会也可能不会在创建后立即开始
(注意:通过立即,它相对于执行循环。)

在上面的代码中,p1p5会在您离开当前执行循环后立即开始倒计时。

为了确保在你想要它们之前不执行promises,你必须将它们包装在一个promise生成函数中。

var p1 = function(){
    return new Promise(function(resolve, reject){
        console.log('p1');
        setTimeout(resolve, 5000, "one");
    });
};

var p2 = function(){
    return new Promise(function(resolve, reject){
        console.log('p2');
        setTimeout(resolve, 3000, "two");
    });
};

var p3 = function(){
    return new Promise(function(resolve, reject){
        console.log('p3');
        setTimeout(resolve, 2000, "three");
    });
};

var p4 = function(){
    return new Promise(function(resolve, reject){
        console.log('p4');
        setTimeout(resolve, 1000, "four");
    });
};

var p5 = function(){
    return new Promise(function(resolve, reject){
        console.log('p5');
        setTimeout(resolve, 4000, "five");
    });
};

对于上述情况,如果您已经知道您拥有的承诺数量,您可以简单地将承诺链接在一起:

p1().then(p2).then(p3).then(p4).then(p5).then(function(){
     // Hurray! All done!
     console.log("All done :)");
});

但是,如果您有可变数量的承诺按顺序链接,则必须使用循环(请参阅@ PitaJ'或Array.reduce

var arrayOfPromiseGeneratingFunctions = [p1, p2, p3, p4, p5]; // Can be of any size.

// Take the first promise-generating function as chain initializer
var initialFn = arrayOfPromiseGeneratingFunctions.shift();

// Here we're effectively doing promise chaining like the simple solution above
var finalPromise = arrayOfPromiseGeneratingFunctions.reduce(function(previousPromise, fn){
    return previousPromise.then(fn)
}, initialFn());

finalPromise.then(function(){
    // Last promise called
});

此解决方案适用于任意数量的顺序执行的promises,因此只要使用函数包装promise即可。

其他一些关于此实施的内容:
1.在示例中,我们将p1到p5包装成一个函数,这样它们就不会在你想要之前以任何方式执行。
2.您可以通过在promise生成函数中添加参数,将结果promise结果从一个传递到另一个。由于第一个参数实际上是最后一个承诺的解析结果。

进一步阅读:https://github.com/kriskowal/q#sequences

答案 1 :(得分:1)

then在创建时立即执行。您必须使用new Promise(function(resolve, reject){ console.log('p1'); setTimeout(resolve, 5000, "one"); }).then(() => { console.log('p2'); setTimeout(resolve, 3000, "two"); }).then(() => { console.log('p3'); setTimeout(resolve, 2000, "three"); }).then(() => { console.log('p4'); setTimeout(resolve, 1000, "four"); }).then(() => { console.log('p5'); setTimeout(resolve, 4000, "five"); }); 来链接操作。

{{1}}

答案 2 :(得分:0)

您可以这样做:

function sequential(promiseArr) {
  var p = Promise.resolve(), i = 0, l = promiseArr.length;
  for (; i < l; i += 1) {
    p = p.then(promiseArr[i]);
  }
  return p;
}

编辑:修正了它。会因为p未初始化而无法启动而失败。

答案 3 :(得分:0)

让我重新解释一下你的问题。

你有一个返回承诺的函数。只有在解决了上一个承诺时,才需要使用不同的参数一次又一次地调用此函数。

让我们想象以下就是这个功能。

function getPromise(arg) {                
      return new Promise(function(resolve){
           setTimeout(resolve, Math.random() * 10000, [arg]);
       }) 
};

这是你的参数列表

var promiseSetup = ['apple', 'orange', 'grapes'];

你可以在这里使用包含函数的对象而不是简单的demo params。

现在我将放下逻辑,它将对每个参数重复执行上述promise函数。这将按顺序完成。

function promiseWaterfall(args, promFunc, idx) {

    if (idx >= args.length)
        return;

    console.log('executing ' + args[idx]);                

    promFunc(args[idx]).then(function(){
        promiseWaterfall(args, promFunc, idx + 1)
    });                
}

<强>解释

上述函数是递归的。只有当前一个获得的承诺得到解决时,它才会使用高级索引值调用自身。

另请注意,每次解析承诺时都可以执行函数。你可以制作&#34; apple&#34;像这样的苹果对象

[{arg: "apple", func: executeApple}]

然后执行此功能,我们记录控制台消息。