系列控制流程与蓝鸟承诺

时间:2016-10-27 20:22:22

标签: javascript bluebird

我有许多承诺,我想按顺序执行它们,但有条件地执行。

例如,我有以下承诺:

getItems()

getItemsSource()

getItemsAlternativeSource()

我想要做的是先尝试getItems()。如果这解析为空值或者如果它抛出错误,我想记录该错误(如果是这种情况),但是然后尝试getItemsSource(),如上所述,如果它没有值解析或抛出错误,如果是这种情况,我想记录错误并尝试getItemsAlternativeSource()

我知道我可以在每个then()catch()中有条件地执行此操作,但这似乎有点多余。有没有更好的方法来处理这种控制流程?

感谢!

2 个答案:

答案 0 :(得分:1)

您可以使用空值作为catch处理程序的返回值:

getItems().catch(function(err) {
    console.warn(err);
    return null; // <==
}).then(function(items) {
    if (items) return items;
    else return getItemsSource().catch(function(err) {
        console.warn(err);
        return null; // <==
    }).then(function(sourceitems) {
        if (items) return items;
        else return getItemsAlternativeSource().catch(function(err) {
            console.warn(err);
            throw new Error("items couldn't be fetched normally, from source, or from alternative source");
        });
    });
});

如果您绝对想避免重复,可以使用这种高度抽象的方法:

var tryAll = [getItems, getItemsSource, getItemsAlternativeSource].reduceRight(function(nextAlternative, fetch) {
    return function() {
        return fetch().then(function(items) {
            if (items) return items;
            else return nextAlternative(); // now we can even call it in two locations
        }, function(err) {
            console.warn(err);
            return nextAlternative(); // without having to resort to catch-then
        });
    };
}, function last() {
    throw new Error("items couldn't be fetched normally, from source, or from alternative source");
});
tryAll();

答案 1 :(得分:1)

我建议你创建一个函数,它接受一个函数数组,这些函数将调用数组中的每个函数,直到返回一些数据。

function getFirstData(array) {
    var index = 0;
    function next() {
        if (index < array.length) {
            return array[index++]().then(function(data) {
                // if we got an answer, return it as the resolve value
                if (data) return data;
                // otherwise, reject so we go to the next one
                return Promise.reject(null);
            }).catch(function(err) {
                if (err) console.err(err);
                return next();
            });
        } else {
            // got to the end of the array without a value
            throw new Error("No data found");
        }
    }
    return Promise.resolve().then(next);
}

var fns = [getItem, getItemsSource, getItemsAlternativeSource];

getFirstData(fns).then(function(data) {
    // got data here
}).catch(function(err) {
    // no data found here
});

如果你想让函数有参数,那么你可以在将它们放入数组之前.bind()函数的参数。

而且,这是使用.reduce()遍历数组的不同实现:

function getFirstData(array) {
    return array.reduce(function(p, fn) {
        return p.then(function(priorData) {
            // if we already got some data, then just return it
            // don't execute any more functions
            if (priorData) return priorData;
            return fn().catch(function(err) {
                console.log(err);
                return null;
            });
        });
    }, Promise.resolve()).then(function(data) {
        if (!data) {
            throw new Error("No data found");
        }        
    });
}