Gro*_*fit 118 javascript node.js promise bluebird
我仍然是相当新的承诺,目前正在使用蓝鸟,但我有一个场景,我不太确定如何最好地处理它.
例如,我在快递应用程序中有一个承诺链,如下所示:
repository.Query(getAccountByIdQuery)
.catch(function(error){
res.status(404).send({ error: "No account found with this Id" });
})
.then(convertDocumentToModel)
.then(verifyOldPassword)
.catch(function(error) {
res.status(406).send({ OldPassword: error });
})
.then(changePassword)
.then(function(){
res.status(200).send();
})
.catch(function(error){
console.log(error);
res.status(500).send({ error: "Unable to change password" });
});
Run Code Online (Sandbox Code Playgroud)
所以我追求的行为是:
所以,目前抓到似乎没有停止的链接,这是有道理的,所以我想知道如果有,我以某种方式迫使链停在基于错误的某一点的方式,或是否有更好的办法构造它以获得某种形式的分支行为,就像有一种情况一样if X do Y else Z
.
任何帮助都会很棒.
Ben*_*aum 122
此行为与同步投掷完全相同:
try{
throw new Error();
} catch(e){
// handle
}
// this code will run, since you recovered from the error!
Run Code Online (Sandbox Code Playgroud)
这是一半.catch
- 能够从错误中恢复.可能需要重新抛出以表明状态仍然是错误:
try{
throw new Error();
} catch(e){
// handle
throw e; // or a wrapper over e so we know it wasn't handled
}
// this code will not run
Run Code Online (Sandbox Code Playgroud)
但是,由于错误会被后来的处理程序捕获,因此单独使用此功能不适用于您的情况.这里真正的问题是,通用的"HANDLE ANYTHING"错误处理程序通常是一种不好的做法,并且在其他编程语言和生态系统中非常不受欢迎.出于这个原因,Bluebird提供了类型和谓词捕获.
增加的优势是您的业务逻辑根本不(并且不应该)必须知道请求/响应周期.查询负责决定客户端获取哪种HTTP状态和错误,以后随着应用程序的增长,您可能希望将业务逻辑(如何查询数据库以及如何处理数据)与发送给客户端的内容分开(什么http状态代码,什么文本和什么响应).
这是我编写代码的方式.
首先,我要.Query
抛出一个NoSuchAccountError
,我将它从Promise.OperationalError
Bluebird已经提供的子类化.如果您不确定如何将错误子类化,请告诉我.
我还要继承它AuthenticationError
,然后做类似的事情:
function changePassword(queryDataEtc){
return repository.Query(getAccountByIdQuery)
.then(convertDocumentToModel)
.then(verifyOldPassword)
.then(changePassword);
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的 - 它非常干净,您可以阅读文本,就像过程中发生的事情的说明手册一样.它也与请求/响应分开.
现在,我将从路由处理程序中调用它:
changePassword(params)
.catch(NoSuchAccountError, function(e){
res.status(404).send({ error: "No account found with this Id" });
}).catch(AuthenticationError, function(e){
res.status(406).send({ OldPassword: error });
}).error(function(e){ // catches any remaining operational errors
res.status(500).send({ error: "Unable to change password" });
}).catch(function(e){
res.status(500).send({ error: "Unknown internal server error" });
});
Run Code Online (Sandbox Code Playgroud)
这样,逻辑就在一个地方,并且如何处理客户端错误的决定都在一个地方,并且它们不会相互混乱.
Esa*_*ija 46
.catch
就像try-catch
声明一样,这意味着你最后只需要一个捕获:
repository.Query(getAccountByIdQuery)
.then(convertDocumentToModel)
.then(verifyOldPassword)
.then(changePassword)
.then(function(){
res.status(200).send();
})
.catch(function(error) {
if (/*see if error is not found error*/) {
res.status(404).send({ error: "No account found with this Id" });
} else if (/*see if error is verification error*/) {
res.status(406).send({ OldPassword: error });
} else {
console.log(error);
res.status(500).send({ error: "Unable to change password" });
}
});
Run Code Online (Sandbox Code Playgroud)
Ber*_*rgi 16
我想知道是否有办法让我以某种方式强迫链条根据错误停在某一点
不可以.你不能真正"结束"一个链,除非你抛出一个泡沫直到结束的例外.请参阅Benjamin Gruenbaum关于如何做到这一点的答案.
他的模式的推导是不区分错误类型,而是使用有错误statusCode
,并body
可以从一个单一的,通用的发送场.catch
处理.根据您的应用程序结构,他的解决方案可能更清晰.
或者,如果有更好的方法来构建它以获得某种形式的分支行为
是的,你可以用promises做分支.但是,这意味着离开链并"返回"嵌套 - 就像你在嵌套的if-else或try-catch语句中所做的那样:
repository.Query(getAccountByIdQuery)
.then(function(account) {
return convertDocumentToModel(account)
.then(verifyOldPassword)
.then(function(verification) {
return changePassword(verification)
.then(function() {
res.status(200).send();
})
}, function(verificationError) {
res.status(406).send({ OldPassword: error });
})
}, function(accountError){
res.status(404).send({ error: "No account found with this Id" });
})
.catch(function(error){
console.log(error);
res.status(500).send({ error: "Unable to change password" });
});
Run Code Online (Sandbox Code Playgroud)
小智 7
我一直在这样做:
你最后留下你的渔获物。当它发生在你的链中途时就抛出一个错误。
repository.Query(getAccountByIdQuery)
.then((resultOfQuery) => convertDocumentToModel(resultOfQuery)) //inside convertDocumentToModel() you check for empty and then throw new Error('no_account')
.then((model) => verifyOldPassword(model)) //inside convertDocumentToModel() you check for empty and then throw new Error('no_account')
.then(changePassword)
.then(function(){
res.status(200).send();
})
.catch((error) => {
if (error.name === 'no_account'){
res.status(404).send({ error: "No account found with this Id" });
} else if (error.name === 'wrong_old_password'){
res.status(406).send({ OldPassword: error });
} else {
res.status(500).send({ error: "Unable to change password" });
}
});
Run Code Online (Sandbox Code Playgroud)
您的其他功能可能如下所示:
function convertDocumentToModel(resultOfQuery) {
if (!resultOfQuery){
throw new Error('no_account');
} else {
return new Promise(function(resolve) {
//do stuff then resolve
resolve(model);
}
}
Run Code Online (Sandbox Code Playgroud)
可能有点晚了,但可以.catch
如下所示进行嵌套:
编辑:我提交这个是因为它通常提供了所要求的功能。但在这种特殊情况下却并非如此。因为正如其他人已经详细解释的那样,.catch
应该恢复错误。例如,您不能在多个 .catch
回调中向客户端发送响应,因为在这种情况下,.catch
没有显式return
解析它,即使您的链没有真正解析,也会导致继续触发,可能导致后续触发并发送对客户端的另一个响应,导致错误并可能妨碍您。我希望这个复杂的句子对你来说有些道理。undefined
.then
.catch
UnhandledPromiseRejection