[英]ExpressJS / NodeJS / Promises: Return early from promise chain
當我在服務器上收到發布請求以創建新游戲時,我會執行幾個查詢。 首先,我搜索用戶是否已經在游戲中,如果是,則返回游戲。 否則,我搜索一個開放的游戲,其中某人正在等待對手並返回該游戲,如果是這樣的話。 最后,如果沒有找到上述狀態的游戲,我會創建一個新游戲並返回。 所以我的代碼看起來像這樣:
.post( function(req, res, next){
...findUsersExistingGame...
.then(function(game){
if(game){ return res.send(game); }
else{
return ...findUserWaitingForOpponentsGame...
}
}
.then(function(game){
if(game){ return res.send(game); }
else{
return ...createNewGame...
}
})
.then(function(game){
return res.send(game);
})
.catch(function(err){
return next(err);
});
我最終會將每個函數重構為輔助函數以提高可讀性,但我需要首先弄清楚鏈接。 我的問題是,如果我在承諾鏈中找到一個游戲(即用戶現有的游戲或其他等待對手的用戶),那么我將返回res.send(游戲); 但是,第三個.then將拋出一個錯誤,因為我之前的.then()語句返回undefined。 如果我想做一個res.send(游戲),我如何早早退出承諾鏈?
選項1:我已經看到了拋出錯誤並明確捕獲它的建議,但這種感覺從根本上說是錯誤的,使用錯誤來控制流量。
選項2:我可以做類似的事情而不是鏈接承諾,但這類似於“承諾/回調地獄”:
.post( function(req, res, next){
...findUsersExistingGame...
.then(function(game){
if(game){ return res.send(game); }
else{
...findUserWaitingForOpponentsGame...
.then(function(game){
if(game){ return res.send(game); }
else{
return ...createNewGame...
.then(function(game){
return res.send(game);
});
}
})
}
}
還有另一種方式(最好是在ES5中,因為我仍然試圖從根本上理解承諾,但ES6的答案也是受歡迎的)?
這里的主要問題是,沿途的每個步驟都有三個可能的返回值:
由於promises只是自然地分離錯誤而沒有錯誤,只要你想以不同的方式處理這三個單獨的返回中的每一個,你就會添加一些自己的分支邏輯。
要使用promise結果干凈地進行分支需要額外的嵌套級別,並且通常沒有理由避免它,因為它將使您的代碼最容易遵循並理解其邏輯。
.post( function(req, res, next) {
findUsersExistingGame(...).then(function(game) {
if (game) return game;
return findUserWaitingForOpponentsGame(...).then(function(game) {
if (game) return game;
// createNewGame() either resolves with a valid game or rejects with an error
return createNewGame(...);
});
}).then(function(game) {
res.send(game);
}, function(err) {
// send an error response here
});
});
請注意這是如何簡化每個階段的返回,並返回下一個嵌套的承諾,使事物鏈,並集中處理將響應發送到一個地方以減少整體代碼。
現在,您可以通過讓每個函數接受之前的游戲值並讓他們檢查是否已經存在有效游戲來隱藏其中一些邏輯,如果是,則他們什么也不做:
.post( function(req, res, next) {
findUsersExistingGame(args)
.then(findUserWaitingForOpponentsGame)
.then(createNewGame)
.then(function(game) {
res.send(game);
}, function(err) {
// send an error response here
});
});
但是,在findUserWaitingForOpponentsGame()
,你必須接受findUsersExistingGame()
解析的確切參數,你必須檢查游戲是否有效。
function findUserWaitingForOpponentsGame(args) {
if (args.game) {
return Promise.resolve(args);
} else {
return doAsyncFindUserWaitingForOpponentsGame(args);
}
}
每個函數都將使用args對象解析,該對象上有任何公共參數,並且具有每個級別可以檢查的.game
屬性。 雖然這為您提供了一個很好的清潔控制流,但它確實在每個函數中創建了額外的代碼,它強制每個函數接受作為前一個函數輸出的參數(因此您可以直接鏈接)。 你可以決定哪個更好。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.