当我在服务器上收到创建新游戏的发布请求时,我执行了几个查询。首先,我搜索用户是否已经在游戏中,如果是,则返回游戏。否则,我会搜索一个有人在等待对手的开放游戏,如果是的话,我会返回那个游戏。最后,如果没有找到上述状态的游戏,我会创建一个新游戏并将其返回。所以我的代码看起来像这样:
.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);
});
为了更好的可读性,我最终会将每个函数重构为辅助函数,但我需要先弄清楚链接。我的问题是,如果我在 promise 链的早期找到一个游戏(即有一个用户的现有游戏或另一个正在等待对手的用户)然后我返回 res.send(game);但是,第三个 .then 将抛出错误,因为我之前的 .then() 语句返回未定义。如果我想执行 res.send(game),我该如何提前从 promise 链中返回?
选项 1:我看到过抛出错误并明确捕获它的建议,但感觉从根本上来说是错误的,即使用错误来控制流程。
选项 2:我可以做这样的事情而不是链接 promise ,但这类似于“ promise /回调 hell ”:
.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 中,因为我仍在尝试从根本上理解 promise ,但也欢迎 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
});
});
请注意这如何简化每个阶段的返回,它返回下一个嵌套的 promise 以使事情链化,它集中处理将响应发送到一个地方以减少整体代码。
现在,您可以通过让每个函数接受之前的游戏值并让它们检查是否已经存在有效游戏来隐藏其中的一些逻辑,如果存在,它们什么都不做:
.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
属性。虽然这为您提供了一个非常干净的控制流,但它确实在每个函数中创建了额外的代码,并且它强制每个函数接受作为前一个函数输出的参数(因此您可以进行直接链接)。您可以决定自己更喜欢哪个。
关于javascript - ExpressJS/NodeJS/ promise : Return early from promise chain,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37096311/