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/elseif/else结构并放弃周围的try/catch会更好

异步函数始终以异步方式运行有多重要,特别是在错误条件下

如果您知道程序处于不适合异步操作继续的状态,是否可以抛出

是的,我个人认为当这是一个与任何异步产生的错误非常不同的错误,并且无论如何都需要单独处理时,这是可以的

如果已知某些用户名无效,因为它们不是数字,而有些用户名将在服务器上被拒绝(例如,因为它们已经被接受),那么您应该始终进行异步!这两种情况下的回调。如果异步错误仅由网络问题等引起,您可能会发出不同的信号

当出现意外错误时,始终可以抛出。如果您需要有效的用户标识,则可能会添加无效的用户标识。如果您希望预测无效的错误并期望调用方处理它们,那么应该使用统一的错误路由,这将是异步函数的回调/拒绝承诺


重复@Timothy:您应该始终记录行为并保持行为的一致性。

回调API理想情况下不应该抛出,但它们确实抛出,因为这很难避免,因为您必须在任何地方都尝试捕获。记住,函数抛出时不需要通过抛出显式抛出错误。此外,用户回调也可以很容易地抛出,例如调用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最终决定,即使异步函数的同步部分抛出的错误也应该拒绝它的承诺,而不是引发同步错误。例如:

异步函数{ 返回21; } 异步函数示例{ console.log功能的同步部分; 抛出新错误失败; const x=等待一些东西; 返回x*2; } 试一试{ console.logbefore调用; example.catch=>{console.logasynchronous:,e.message;}; console.logafter调用; }抓住e{ console.logsynchronous:,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")
})