当承诺拒绝时,顺序的承诺不会停止

时间:2017-05-24 04:47:38

标签: javascript promise

我有一份承诺清单。

var p1 = {
    run: function () {
        return new Promise(function (resolve, reject) {
            setTimeout(function () {
                resolve("Promise 1 done");
            }, 2000);
        })
    }
};

var p2 = {
    run: function () {
        return new Promise(function (resolve, reject) {
            setTimeout(function () {
                reject("Promise 2 reject");
            }, 1000);
        })
    }
};

var p3 = {
    run: function () {
        return new Promise(function (resolve, reject) {
            setTimeout(function () {
                resolve("Promise 3 done");
            }, 1500);
        })
    }
};

我想按顺序执行[p1,p2,p3]。我写了一个函数Process.sequence,就像Promise.all()一样(当所有承诺都解决时解决,并在承诺拒绝后立即拒绝)

Process = {
    sequence: function(promises){
        window.promises = promises;
        return new Promise(function (resolve, reject) {
            promises.reduce(function (sequence, promise) {
                return sequence.then(function () {
                    return promise.run();
                }).then(function (result) {
                    console.log(result);
                    if (promises.indexOf(promise) == promises.length - 1) {
                        resolve("All Done");
                    }
                }).catch(function (reason) {
                    reject(reason);
                });
            }, Promise.resolve());
        });
    }
};

但是当我运行Process.sequence ...

Process.sequence([p1,p2,p3]).then(function(result){
    console.log(result);
}, function(reason){
    console.log(reason);
});

... p3仍然执行p2之前已被拒绝。

以下是我期望的结果:

Promise 1 done
Promise 2 reject

但这是真正的结果:

Promise 1 done
Promise 2 reject
Promise 3 done

我的功能Process.sequence有什么问题?

更新

感谢@JaromandaX的支持。函数Process.sequence应该是这样的。

Process = {
    sequence: function(promises) {
        return promises.reduce(function(sequence, promise) {
            return sequence.then(function() {
                return promise.run();
            }).then(function(result) {
                console.log(result);
            });
        }, Promise.resolve()).then(function() {
            return "All Done";
        });
    }
};

1 个答案:

答案 0 :(得分:2)

如果您希望结果包含所有已完成的值,并且只有在完成所有先前的值时才会创建承诺("运行"),您应该进行一些更改:

  • 让你的循环异步,因为你只能知道在前一个承诺解决后是否继续下一个承诺。
  • 当承诺拒绝时停止循环
  • 在进展时将结果连接到数组

此外,我不会称变量"承诺"当它不是一个承诺对象......那只会带来混乱。称之为task或其他什么。这里的承诺是task.run()方法返回的内容。

以下是我建议的方法:



// The p1, p2, p3 objects have been written more concisely using a helper function:
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));

const p1 = { run: _ => wait(2000).then(_ => "Promise 1 fulfilled") };
const p2 = { run: _ => wait(1000).then(_ => { throw "Promise 2 rejected" }) };
const p3 = { run: _ => wait(1500).then(_ => "Promise 3 fulfilled") };

const Process = {
    sequence: function (tasks) {
        return (function loop(results) {
            return results.length >= tasks.length 
                // All promises were fulfilled: return the results via a promise
                ? Promise.resolve(results) 
                // Create the next promise
                : tasks[results.length].run()
                    // When it fulfills, collect the result, and chain the next promise
                    .then(value => loop(results.concat(value)))
                    // When it rejects, return a rejected promise with 
                    // the partial results and the reason of rejection
                    .catch(reason => { throw results.concat(reason) });
        })([]); // Start with an empty results array 
    }
};

console.log('Wait for the results to come in...');
Process.sequence([p1, p2, p3]).then(function(result){
    console.log('Fulfilled: ', result);
}).catch(function(reason){
    console.log('Rejected: ', reason);
});




随着浏览器开始支持async/await,您还可以使用这个更具程序性的代码:



const wait = ms => new Promise(resolve => setTimeout(resolve, ms));

const p1 = { run: _ => wait(2000).then(_ => "Promise 1 fulfilled") };
const p2 = { run: _ => wait(1000).then(_ => { throw "Promise 2 rejected" }) };
const p3 = { run: _ => wait(1500).then(_ => "Promise 3 fulfilled") };

const Process = {
    sequence: async function (tasks) {
        const results = [];
        for (let task of tasks) {
            try {
                results.push(await task.run());
            } catch(err) {
                throw results.concat(err);
            }
        }
        return results;
    }
};

console.log('Wait for the results to come in...');
Process.sequence([p1, p2, p3]).then(function(result){
    console.log('Fulfilled: ', result);
}).catch(function(reason){
    console.log('Rejected: ', reason);
});