按顺序执行承诺 [英] Executing promises in a sequence

查看:44
本文介绍了按顺序执行承诺的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此页面中的示例.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, "二");});var p3 = new Promise(function(resolve, reject){console.log('p3');setTimeout(resolve, 2000, "三");});var p4 = new Promise(function(resolve, reject){console.log('p4');setTimeout(resolve, 1000, "四");});var p5 = new Promise(function(resolve, reject){console.log('p5');setTimeout(resolve, 4000, "五");});Promise.all([p1, p2, p3, p4, p5]).then(function(value) {控制台日志(值);}, 函数(原因){控制台日志(原因)});

输出

p1、p2、p3、p4、p5

所有 p1-p5 都同时执行,但如果我想对它进行排序.一旦 p1 解析,则应调用 p2,然后调用 p3.

我如何顺序/链接(而不是并行)承诺而不是一次迭代.

如果我手动等待每个承诺,就会造成回调地狱.请指教.

解决方案

首先,promise 可能会也可能不会在创建后立即开始执行.
(注意:by 立即,它是相对于执行循环的.)

在上面的代码中,p1p5 一旦离开当前执行循环就开始倒计时.

为了确保承诺不会在您希望之前执行,您必须将它们包装在一个承诺生成函数中.

var p1 = function(){返回新的承诺(函数(解决,拒绝){console.log('p1');setTimeout(resolve, 5000, "one");});};var p2 = 函数(){返回新的承诺(函数(解决,拒绝){console.log('p2');setTimeout(resolve, 3000, "二");});};var p3 = 函数(){返回新的承诺(函数(解决,拒绝){console.log('p3');setTimeout(resolve, 2000, "三");});};var p4 = 函数(){返回新的承诺(函数(解决,拒绝){console.log('p4');setTimeout(resolve, 1000, "四");});};var p5 = 函数(){返回新的承诺(函数(解决,拒绝){console.log('p5');setTimeout(resolve, 4000, "五");});};

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

p1().then(p2).then(p3).then(p4).then(p5).then(function(){//万岁!全部做完!console.log("全部完成:)");});

但是,如果您有可变数量的 promise 依次链接,则必须使用循环(请参阅@PitaJ 的回答)或 Array.reduce.

var arrayOfPromiseGeneratingFunctions = [p1, p2, p3, p4, p5];//可以是任意大小.//将第一个承诺生成函数作为链初始值设定项var initialFn = arrayOfPromiseGeneratingFunctions.shift();//这里我们像上面的简单解决方案一样有效地进行承诺链接var finalPromise = arrayOfPromiseGeneratingFunctions.reduce(function(previousPromise, fn){返回 previousPromise.then(fn)}, initialFn());finalPromise.then(function(){//最后调用的承诺});

这个方案适用于任意数量的顺序执行的promise,只要你用一个函数包装promise即可.

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

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

An example from this page. 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)
});

Output

p1, p2, p3, p4, p5

All p1-p5 are executed at once but let's say if I want to sequence it. Once p1 resolves, then p2 should be called, and then p3.

How can I sequence/chain (instead of parallel) the promises instead of an iteration through all at once.

It's creating callback hell if I do a manual approach on waiting for each promise. Please advise.

解决方案

Firstly, promises may or may not start executing immediately after creation.
(Note: by immediately, it is relative to the execution loop.)

In your above code, p1 to p5 starts counting down as soon as you leave the current execution loop.

To ensure the promises does not get executed before you want them to, you would have to wrap them in a promise generating function.

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

For the above case, if you already know the number of promises you have, you can simply chain the promises together:

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

However, if you have a variable amount of promises to chain in sequence, you would have to make use of loops (see @PitaJ's answer) or 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
});

This solution is suitable for an arbitrary number of sequentially executed promises, so as long as you wrap the promises with a function.

Some other catches about this implementation:
1. In the example we wrap p1 to p5 into a function, so that they don't get executed in any way before you want it to.
2. You can pass results promise results from one to another, by adding the parameter in the promise-generating function. Since the first parameter would effectively be the resolve result of the last promise.

Further reading: https://github.com/kriskowal/q#sequences

这篇关于按顺序执行承诺的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆