[英]how to break promise chain
我是這樣的承諾,
function getMode(){
var deferred = Promise.defer();
checkIf('A')
.then(function(bool){
if(bool){
deferred.resolve('A');
}else{
return checkIf('B');
}
}).then(function(bool){
if(bool){
deferred.resolve('B');
}else{
return checkIf('C');
}
}).then(function(bool){
if(bool){
deferred.resolve('C');
}else{
deferred.reject();
}
});
return deferred.promise;
}
checkIf
返回一個promise,是的checkIf
無法修改 。
我如何在第一場比賽中脫穎而出? (除了明確拋出錯誤之外的任何其他方式?)
除了明確拋出錯誤之外的任何方式?
你可能需要拋出一些東西,但它不一定是錯誤的。
大多數promise實現都有方法catch
接受第一個參數作為錯誤類型(但不是全部,而不是ES6的承諾),在這種情況下它會有所幫助:
function BreakSignal() { }
getPromise()
.then(function () {
throw new BreakSignal();
})
.then(function () {
// Something to skip.
})
.catch(BreakSignal, function () { })
.then(function () {
// Continue with other works.
});
我添加了破解我自己的promise庫的最近實現的能力。 如果你使用的是ThenFail (你可能沒有),你可以寫下這樣的東西:
getPromise()
.then(function () {
Promise.break;
})
.then(function () {
// Something to skip.
})
.enclose()
.then(function () {
// Continue with other works.
});
我會使用coroutines / spawns ,這會導致更簡單的代碼:
function* getMode(){
if(yield checkIf('A'))
return 'A';
if(yield checkIf('B'))
return 'B';
if(yield checkIf('C'))
return 'C';
throw undefined; // don't actually throw or reject with non `Error`s in production
}
如果你沒有發電機那么總是有traceur或6to5。
我想你不想要鏈條。 以同步的方式,你已經寫過了
function getMode(){
if (checkIf('A')) {
return 'A';
} else {
if (checkIf('B')) {
return 'B';
} else {
if (checkIf('C')) {
return 'C';
} else {
throw new Error();
}
}
}
}
這就是它應該如何轉化為承諾:
function getMode(){
checkIf('A').then(function(bool) {
if (bool)
return 'A';
return checkIf('B').then(function(bool) {
if (bool)
return 'B';
return checkIf('C').then(function(bool) {
if (bool)
return 'C';
throw new Error();
});
});
});
}
承諾中沒有if else
假裝。
你可以使用return { then: function() {} };
.then(function(bool){
if(bool){
deferred.resolve('A');
return { then: function() {} }; // end/break the chain
}else{
return checkIf('B');
}
})
return語句返回一個“then-able”,只是then方法什么都不做。 當從then()函數返回時,then()將嘗試從thenable中獲取結果。 當時的“then”接受回調,但在這種情況下永遠不會被調用。 所以“then()”返回,並且鏈的其余部分的回調不會發生。
您可以創建firstSucceeding
函數,該函數將返回第一個成功操作的值或拋出NonSucceedingError
。
我已經使用過ES6承諾,但您可以調整算法以支持您選擇的promise接口。
function checkIf(val) { console.log('checkIf called with', val); return new Promise(function (resolve, reject) { setTimeout(resolve.bind(null, [val, val === 'B']), 0); }); } var firstSucceeding = (function () { return function (alternatives, succeeded) { var failedPromise = Promise.reject(NoneSucceededError()); return (alternatives || []).reduce(function (promise, alternative) { return promise.then(function (result) { if (succeeded(result)) return result; else return alternative(); }, alternative); }, failedPromise).then(function (result) { if (!succeeded(result)) throw NoneSucceededError(); return result; }); } function NoneSucceededError() { var error = new Error('None succeeded'); error.name = 'NoneSucceededError'; return error; } })(); function getMode() { return firstSucceeding([ checkIf.bind(null, 'A'), checkIf.bind(null, 'B'), checkIf.bind(null, 'C') ], function (result) { return result[1] === true; }); } getMode().then(function (result) { console.log('res', result); }, function (err) { console.log('err', err); });
我喜歡到目前為止發布的許多答案,以減輕q自述文件所謂的“厄運金字塔”。 為了便於討論,我將添加我在搜索周圍以查看其他人正在做什么之前插入的模式。 我寫了一個像
var null_wrap = function (fn) {
return function () {
var i;
for (i = 0; i < arguments.length; i += 1) {
if (arguments[i] === null) {
return null;
}
}
return fn.apply(null, arguments);
};
};
和我做了完全類似於@ vilicvane的答案,除了不throw new BreakSignal()
我寫return null
,並包裹所有后續.then
回調在null_wrap
像
then(null_wrap(function (res) { /* do things */ }))
我認為這是一個很好的答案b / c它避免了大量的縮進和b / c OP專門要求一個不throw
的解決方案。 那說,我可以回去使用更像@vilicvane做的事情b / c某些庫的承諾可能會返回null
以表示除了“打破鏈條”以外的東西,這可能會令人困惑。
這是一個更多的評論/答案的呼吁,而不是“這絕對是做到這一點的方式”答案。
可能會在這里晚會,但我最近發布了一個使用生成器的答案和將回答這個問題的co
庫(參見解決方案2):
代碼如下:
const requestHandler = function*() {
const survey = yield Survey.findOne({
_id: "bananasId"
});
if (survey !== null) {
console.log("use HTTP PUT instead!");
return;
}
try {
//saving empty object for demonstration purposes
yield(new Survey({}).save());
console.log("Saved Successfully !");
return;
}
catch (error) {
console.log(`Failed to save with error: ${error}`);
return;
}
};
co(requestHandler)
.then(() => {
console.log("finished!");
})
.catch(console.log);
您幾乎可以編寫實際上異步的同步代碼!
希望能幫助到你!
嘗試使用像這樣的庫:
https://www.npmjs.com/package/promise-chain-break
db.getData()
.then(pb((data) => {
if (!data.someCheck()) {
tellSomeone();
// All other '.then' calls will be skiped
return pb.BREAK;
}
}))
.then(pb(() => {
}))
.then(pb(() => {
}))
.catch((error) => {
console.error(error);
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.