我有许多承诺,我想按顺序执行它们,但有条件地执行。
例如,我有以下承诺:
getItems()
getItemsSource()
getItemsAlternativeSource()
我想要做的是先尝试getItems()
。如果这解析为空值或者如果它抛出错误,我想记录该错误(如果是这种情况),但是然后尝试getItemsSource()
,如上所述,如果它没有值解析或抛出错误,如果是这种情况,我想记录错误并尝试getItemsAlternativeSource()
。
我知道我可以在每个then()
或catch()
中有条件地执行此操作,但这似乎有点多余。有没有更好的方法来处理这种控制流程?
感谢!
答案 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");
}
});
}