实现Promise.all和Promise.settle的混合

时间:2015-09-08 22:32:43

标签: javascript promise bluebird

我需要实现一个Promise.all版本,它会接受一系列承诺,并像往常一样返回结果,并且还会解决所有承诺,就像Promise.settle在{Bluebird中所做的那样1}}库,除了我不能使用Bluebird,并且必须仅依赖于标准的promise协议。

实施起来会非常复杂吗?或者在这里问一下如何实现它的想法太过分了?我真的希望不是,所以我问,如果有人可能之前实现它,分享如何做正确的想法。

这样做的前提是能够在调用完成后需要执行commit / rollback的数据库事务中使用它,并且它仍然没有松散的承诺仍在尝试解决交易电话。

编辑:提供给另一个问题的链接非常有用,但它并不是对所提问题的完整答案。通用settle是一个很好的例子,它有很多帮助,但它需要简化并包装成all逻辑,以适应前面描述的事务场景。

3 个答案:

答案 0 :(得分:7)

我认为jfriend的解决方案过于复杂,因为它构建在settle之上,它运行信号量并执行许多奇怪的东西,而不是使用像.all这样的内置原语。 / p>

相反,如果我们构建Bluebird的较新的reflect原语(在本机承诺中实现它),我们可以获得更清晰的API和实现:

function reflect(promise){
    return promise.then(x => ({state: "fulfilled", value: x}), // arrows, assume nodejs
                        e => ({state: "rejected" , value: e}));
}

除了反思之外,我们可以轻松地构建其他基元:

function settle(promises){
    return Promise.all(promises.map(reflect)); // much cleaner
}

如果我们想等待,然后根据值解决/拒绝,那就是:

function allWait(promises){
    return settle(promises).then(results => {
       var firstFailed = results.find(r => r.state === "rejected");
       if(firstFailed) throw firstFailed.value;
       return results; 
    });
}

答案 1 :(得分:3)

the other question的通用promiseSettle()函数的基础上,您可以执行此操作并同时拥有通用settle()类型函数和更具体的版本作为它的包装。这将为您提供执行大量.settle()类型行为的通用功能,并具有您自己的特定风格,并根据需要构建其他特定风格:

所以,这里是通用promiseSettle(),它返回所有承诺的状态,并且只有在完成所有传入的承诺后才会解决:

function promiseSettle(promises) {
    return new Promise(function(resolve) {
        var remaining = promises.length;
        // place to store results in original order
        var results = new Array(remaining);

        function checkDone() {
            if (--remaining === 0) {
                resolve(results);
            }
        }

        promises.forEach(function(item, index) {
            // check if the array entry is actually a thenable
            if (typeof item.then === "function") {
                item.then(function(value) {
                    // success
                    results[index] = {state: "fulfilled", value: value};
                    checkDone();
                }, function(err) {
                    // reject error
                    results[index] = {state: "rejected", value: err};
                    checkDone();
                });
            } else {
                // not a thenable, just return the item itself
                results[index] = {state: "fulfilled", value: item}
                --remaining;
            }
        });
        // special case for zero promises passed
        if (remaining === 0) {
            resolve(results);
        }
    });
}

而且,这里有一个包装器,可以为您提供特定的行为:

// Either fulfills with an array of results or
// rejects with the first error, but it does not do either
// until all promises have completed which makes it different than
// promise.all()
function promiseSettleAll(promises) {
    return promiseSettle(promises).then(function(results) {
        for (var i = 0; i < results.length; i++) {
            if (results[i].state !== "fulfilled") {
                // reject with the first error found
                throw results[i].value;
            }
        }
        // all were successful, return just array of values
        return results.map(function(item) {return item.value;});
    });
}

答案 2 :(得分:0)

在所有研究,编写,测试和优化的最后,它变成了一个专注于此类事物的库(spex)。

具体来说,方法batch是实现所描述逻辑融合的方法。

我不是在这里重新发布its source code,因为它现在a lot more比问题中原先要求的那样。{/ p>