什么更快:try catch vs Promise

Posted

技术标签:

【中文标题】什么更快:try catch vs Promise【英文标题】:What is faster: try catch vs Promise 【发布时间】:2017-07-27 16:48:03 【问题描述】:

我听到这样一种意见,您应该完全避免使用 try/catch,因为它需要很多资源。那么,promise 错误处理可以更快吗?还是根本不重要?

function f(somethingDangerous) 
  return new Promise((resolve, reject) => 
    // try 
    //   somethingDangerous();
    //   resolve();
    //  catch (err) 
    //   reject(err);
    // 

    // VS

    somethingDangerous();
    resolve();
  ).catch((err) => 
    console.error('Catched: ' + err);
  );


f(() => throw 'DANGEROUS THING';);

UPD:我知道 try/catch 不适用于内部的异步代码。我只是想知道是否有任何理由因为性能问题而避免使用 try/catch?以上两种方法有什么区别吗?

UPD2:试图和我的马赛跑:) https://jsperf.com/try-catch-vs-promise

【问题讨论】:

我通常的建议:Race your horses. 你在哪里读到的?请引用您的消息来源,以便我们责怪他们。 @Bergi,实际上我不记得了。就在某个地方……这个想法引发了这个问题。也许我只是不明白一些事情。这就是我问的原因。因为这句话对我来说似乎很可疑。 请注意 .catch(e => Promise.reject(e)) 是 as pointless as .then(r => Promise.resolve(r)) 并且应该从您的赛车代码中删除 你的“马”会产生不同的结果...Firefox,try/catch 快 4%,Chrome 慢 11%...据我所知,每个 Promise 库都使用 try/无论如何都要在内部捕获 【参考方案1】:

您应该将 Promises 用于异步函数,而不是其他。不要把它们当作错误 monad 来滥用,那样会浪费资源,而且它们固有的异步性会让一切变得更麻烦。

当你有同步代码时,使用try/catch进行异常处理。

/* Wrong */
return new Promise(function(resolve, reject) 
    resolve(x / y);
).catch(err => NaN)

/* Right */
try 
    return x / y;
 catch(e) 
    return NaN;

如果你已经有promise代码,你可以在某些情况下避免这种情况:当你希望异常拒绝promise时。在这些情况下,你应该让你的 Promise 的内置错误处理来完成它的工作,而不是通过一个额外但毫无意义的 try/catch 层来使所有事情复杂化:

/* Wrong */
new Promise(function(resolve, reject) 
    try  // when used synchronous in the executor callback
        …
        resolve(somethingSynchronous());
     catch (e) 
        reject(e);
    
);

/* Right */
new Promise(function(resolve, reject) 
    …
    resolve(somethingExceptionally());
);
/* Wrong */
….then(function(res) 
    try 
        …
        return somethingExceptionally();
     catch(e) 
        return Promise.reject(e);
    
).…

/* Right */
….then(function(res) 
    …
    return somethingExceptionally();
).…

【讨论】:

我添加了一个滥用 Promise 的示例,其中应该使用 try/catch。我希望它能很好地为您提供答案。 @naomik 谢谢,但是抛出异常的部门非常罕见:-)(是的,ToNumber 演员可以做到) 而且我已经认为一切都必须放入一个 monad ^^, 试试 const c = await someFunction(); 怎么样? doSomething(c) catch (e) console.error(e) 最后 doSomethingElse() 。这可以写成 someFunction().then(c => doSomething(c)).catch(e => console.error(e)).finally(() => doSomethingElse()),但是性能差异是什么?为什么不应该使用第一种方法,还是我回答错了? @Mattias 不,我的回答只是说你不应该自己拒绝错误处理程序的承诺。您的代码的两个版本都很好,第一个版本甚至可能通过引擎得到更好的优化。【参考方案2】:

try/catch 成语在你有完整的synchronous 代码时工作得很好,但是asynchronous 操作使它无用,不会捕获任何错误。即,该函数将在外部堆栈运行并到达最后一行时开始其进程而没有任何错误。如果将来某个时间在异步函数内部发生错误,则不会捕获任何内容。

当我们使用Promises 时,您可能会说“我们已经失去了错误处理”。没错,我们不需要在这里做任何特别的事情来传播错误,因为我们返回了一个 Promise,并且内置了对错误流的支持。

【讨论】:

这不是真的,因为我们现在有 async/await。有了它的使用,我们现在可以认为所有代码都是同步的。 并非如此,因为您可以在 try 块中等待异步调用【参考方案3】:

基于此基准,我发现大多数应用程序的性能似乎不会受到此类决定的影响。

https://jsperf.com/try-catch-vs-promise

注意:try/catch 至少在使用“async/await”时确实适用于异步代码!

【讨论】:

以上是关于什么更快:try catch vs Promise的主要内容,如果未能解决你的问题,请参考以下文章

Promise的catch()函数

用一级 try ... catch 捕获 JavaScript Promise 中的错误

每个 Promise-chain -> try/catch/await 指南都在教导危险的约定吗? [关闭]

javascript Try-Catch Uncaught Promise Error

无法使用 try-catch 处理未处理的 Promise Rejection

结合element的rule表单校验,使用await获取promise的reject内容,使用try catch方法