经过大量谷歌搜索后,我无法找到一个明确的示例,说明如何避免对每个 catch 进行编程以确定 Promise 拒绝错误是程序性错误还是操作性错误。将此与提供 callback(error, params...) 的 Node 回调模式进行比较,在 error 参数中明确提供操作错误,并通过抛出链处理编程错误。
请告诉我我犯了一个菜鸟错误,对此我错过了一个简单的答案。
编辑 Node v10.0.0 现在通过添加错误代码解决了这个问题。
感谢 RisingStack 将此发送到我的收件箱:
https://blog.risingstack.com/node-js-10-lts-feature-breakdown
...正式但相当简洁(一如既往):
https://nodejs.org/api/errors.html#errors_error_code
考虑一个常见的例子:
function logMeIn (email, password, login_token) {
selectFromDbByEmailAndCheckPwAndReturnId (email, password)
.then(id => { return updateUserIdLoginToken(id, login_token); })
.catch(error => {
// all rejects and throws end up here
console.log(error);
})
})
function selectFromDbByEmailAndCheckPwAndReturnId (email, password) {
return new Promise((resolve, reject) => {
db.sql.query( /* params */, (error, results) => {
blarg = 1; // <-- reference error, programmatic
// do your SELECT * FROM Users where email=? ... etc.
if (error) {
return reject(error); // <-- operational sql error
:
:
if (resultsRowsFromQuery.length === 0) {
// vvvvv operational error: user not found
return reject(new Error("User not in database"));
}
:
// hash password & salt, etc etc etc ...
:
return resolve(resultRowsFromQuery[0].id);
});
});
}
// no need to code out updateUserIdLoginToken...
在此示例中,catch 将捕获程序错误和操作错误,我必须通过程序 catch 来确定是哪一个。如果我想向用户返回他们的电子邮件未找到的事实,我不能只使用消息,因为我可能会不小心返回引用错误消息。 (尴尬!)
但是,与 sql.query 模式相比,很明显该错误是可操作的,因为如果 blarg=1 不在 promise 中,它会冒泡到更高的级别。
关于拒绝值应该是什么以及如何区分的文档很少。我考虑过使用 resolve(new Error()) 以便我的成功实现函数确定是否存在操作错误并为程序错误保存 .catch,但这很愚蠢。
那里有很多不好的信息,因为它在过去 7 年里经常引用 bluebird、Q、A+ 和 ES6……很难找到 ES6 Node/7/9 的例子……[我什至见过声称使用 .then(func A(), func B()).catch() 的链接会将编程错误发送给 B 而不是 catch()。哈哈。]
想法?
编辑 #1:请求无 promise 示例:
function logMeIn (email, password, login_token) {
try {
selectFromDbByEmailAndCheckPwAndReturnId (email, password, (error, id) => {
if (error) {
console.log("Operational error:", error)
return;
}
// no error, got id, do next step...
updateUserIdLoginToken(id, login_token, error => {
// do next thing, like return res.render() or something...
});
});
} catch (e) {
console.error("Programmatic error:", e);
}
})
function selectFromDbByEmailAndCheckPwAndReturnId (email, password, callback) {
db.sql.query( /* params */, (error, results) => {
blarg = 1; // <-- reference error, programmatic
// do your SELECT * FROM Users where email=? ... etc.
if (error) {
return callback(error, null);
}
:
:
if (resultsRowsFromQuery.length === 0) {
// vvvvv operational error: user not found
return callback(new Error("User not in database"), null);
}
:
// hash password & salt, etc etc etc ...
:
return callback(null, id);
});
}
最佳答案
您对 Node 式代码和基于 promise 的代码期望过高。两种异步函数都无法区分操作错误和编程错误的概念,您可以从字面上抛出/拒绝任何东西,这就是为什么您没有找到太多关于它的文档的原因。这两种模式都是异步代码流的原语,仅此而已。 Node 式版本有点笨拙,因为它允许传播同步和异步错误(您需要 try-catch 和 if(error) 来处理所有错误)。尽管他们应该只使用异步版本。在单个函数中使用两个“错误 channel ”不是一个功能,它只是行为不端的代码。
Node 样式和基于 promise 的异步代码都不应抛出常规同步错误。因此不要使用这两种不同的错误传播 channel 来区分编程错误和操作错误。
所以要回答这个问题,您如何区分它们?就像处理常规同步代码一样,您必须引入自己的抽象:
OperationalError 类,使用任意数量的子类,并使您的顶级代码区分 OperationalError-s 和任何其他类型的错误。这是我的建议。关于javascript - promise .catch() : how to identify the differences between operational rejects and programmatical throws,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49225968/