Javascript 异步API是否应该同步抛出?
我正在编写一个JavaScript函数,它发出HTTP请求并返回对结果的承诺(但这个问题同样适用于基于回调的实现) 如果我立即知道为函数提供的参数无效,那么函数应该同步抛出,还是返回被拒绝的承诺(或者,如果您愿意,使用Javascript 异步API是否应该同步抛出?,javascript,asynchronous,promise,api-design,Javascript,Asynchronous,Promise,Api Design,我正在编写一个JavaScript函数,它发出HTTP请求并返回对结果的承诺(但这个问题同样适用于基于回调的实现) 如果我立即知道为函数提供的参数无效,那么函数应该同步抛出,还是返回被拒绝的承诺(或者,如果您愿意,使用错误实例调用回调) 异步函数始终以异步方式运行有多重要,特别是在错误条件下?如果您知道程序处于不适合异步操作继续的状态,则抛出是否可以 e、 g: 最终,是否同步投掷取决于你,你可能会发现双方都有争论的人。重要的是记录行为并保持行为的一致性 我的看法是,您的第二个选择——将错误传递
错误
实例调用回调)
异步函数始终以异步方式运行有多重要,特别是在错误条件下?如果您知道程序处于不适合异步操作继续的状态,则抛出是否可以
e、 g:
最终,是否同步投掷取决于你,你可能会发现双方都有争论的人。重要的是记录行为并保持行为的一致性
我的看法是,您的第二个选择——将错误传递到回调中——似乎更优雅。否则,您将得到如下代码:
try {
getUserById(7, function (response) {
if (response.isSuccess) {
//Success case
} else {
//Failure case
}
});
} catch (error) {
//Other failure case
}
这里的控制流有点混乱
似乎最好在回调中使用一个if/else if/else
结构,并放弃周围的try/catch
异步函数始终以异步方式运行有多重要,特别是在错误条件下
如果您知道程序处于不适合异步操作继续的状态,则抛出是否可以
是的,我个人认为当这是一个与任何异步产生的错误非常不同的错误,并且无论如何都需要单独处理时,这是可以的
如果已知某些用户标识无效,因为它们不是数字,而服务器上会拒绝某些用户标识(例如,因为它们已经被使用),那么您应该为这两种情况一致地进行(异步!)回调。如果异步错误仅由网络问题等引起,您可能会发出不同的信号
当出现“意外”错误时,您总是可以抛出。如果您需要有效的用户标识,则可能会添加无效的用户标识。如果您希望预测无效的错误并期望调用方处理它们,那么应该使用“统一”错误路由,这将是异步函数的回调/拒绝承诺
重复@Timothy:您应该始终记录行为并保持行为的一致性。回调API理想情况下不应该抛出,但它们确实抛出,因为这很难避免,因为您必须在任何地方都尝试捕获。请记住,函数不需要通过throw
显式抛出错误。另外,用户回调也可以很容易地抛出,例如调用JSON.parse
,而无需try-catch
这就是代码的样子,它的行为符合这些理想:
readFile("file.json", function(err, val) {
if (err) {
console.error("unable to read file");
}
else {
try {
val = JSON.parse(val);
console.log(val.success);
}
catch(e) {
console.error("invalid json in file");
}
}
});
必须使用两种不同的错误处理机制确实不方便,因此,如果您不想让您的程序成为一个脆弱的纸牌屋(不编写任何try-catch),您应该使用承诺,将所有异常处理统一到一种机制下:
readFile("file.json").then(JSON.parse).then(function(val) {
console.log(val.success);
})
.catch(SyntaxError, function(e) {
console.error("invalid json in file");
})
.catch(function(e){
console.error("unable to read file")
})
这在很大程度上是一个意见问题。无论你做什么,都要始终如一地做,并清楚地记录下来
我可以提供的一条客观信息是,在JavaScript的异步
函数的设计中,这是很多讨论的主题,您可能知道,这些函数隐式地返回了对其工作的承诺。您可能还知道,在第一个等待
或返回
之前的异步
函数部分是同步的;它只在等待或返回时变为异步
TC39最终决定,即使在async
函数的同步部分抛出错误,也应该拒绝它的承诺,而不是引发同步错误。例如:
异步函数someAsyncStuff(){
返回21;
}
异步函数示例(){
log(“功能的同步部分”);
抛出新错误(“失败”);
const x=等待someAsyncStuff();
返回x*2;
}
试一试{
console.log(“通话前”);
catch(e=>{console.log(“异步:”,e.message);});
console.log(“通话后”);
}捕获(e){
日志(“同步:”,e.message);
}
理想情况下,您应该有一个多层体系结构,如控制器、服务等。如果您在服务中进行验证,请立即抛出,并在控制器中设置一个catch块,以捕获错误格式并发送适当的http错误代码。通过这种方式,您可以集中所有错误的请求处理逻辑。如果你处理每一种情况,你最终会写更多的代码。但这正是我要做的。取决于您的用例还可以查看一下,如果readFile抛出异常,它将不会被那里定义的catch函数捕获。但是如果readfile返回一个承诺,那么它就工作了
readFile("file.json").then(JSON.parse).then(function(val) {
console.log(val.success);
})
.catch(SyntaxError, function(e) {
console.error("invalid json in file");
})
.catch(function(e){
console.error("unable to read file")
})