Javascript 异步API是否应该同步抛出?

Javascript 异步API是否应该同步抛出?,javascript,asynchronous,promise,api-design,Javascript,Asynchronous,Promise,Api Design,我正在编写一个JavaScript函数,它发出HTTP请求并返回对结果的承诺(但这个问题同样适用于基于回调的实现) 如果我立即知道为函数提供的参数无效,那么函数应该同步抛出,还是返回被拒绝的承诺(或者,如果您愿意,使用错误实例调用回调) 异步函数始终以异步方式运行有多重要,特别是在错误条件下?如果您知道程序处于不适合异步操作继续的状态,则抛出是否可以 e、 g: 最终,是否同步投掷取决于你,你可能会发现双方都有争论的人。重要的是记录行为并保持行为的一致性 我的看法是,您的第二个选择——将错误传递

我正在编写一个JavaScript函数,它发出HTTP请求并返回对结果的承诺(但这个问题同样适用于基于回调的实现)

如果我立即知道为函数提供的参数无效,那么函数应该同步抛出,还是返回被拒绝的承诺(或者,如果您愿意,使用
错误
实例调用回调)

异步函数始终以异步方式运行有多重要,特别是在错误条件下?如果您知道程序处于不适合异步操作继续的状态,则抛出
是否可以

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")
})