JavaScript错误处理的最佳实践是什么?

149

我希望开始让我的JavaScript代码更加健壮,我找到了很多使用trycatchfinallythrow的文档,但我并没有从专家那里找到大量关于何时以及在哪里抛出错误的建议。

  • 每个代码片段都应该包含try/catch吗?
  • 是否有更多像这样的建议,说明在什么时候应该捕获错误?
  • 相较于在生产中让代码悄无声息地失败,引发错误是否存在缺点?
  • 对于服务器日志记录JS错误来说,这是一种有效的策略吗?
  • 还有其他需要注意的问题关于在应用程序中捕获错误吗?

如果您了解任何具有优秀章节或深入解释错误处理的书籍,我也非常愿意听取建议。 《Eloquent JavaScript》谈到了这个问题,但对问题并没有很具体指导性和明确的观点。

感谢您能提供的任何建议!


当出现问题时,它肯定取决于您失败的程度以及可能的错误消息数量。您不想因为错误日志目录已满而失败,对吧?- 您是否在这里查看过?http://stackoverflow.com/search?q=error+logging+javascript - mplungjan
@mplungjan - 我确实浏览了那里的答案,但似乎没有多少是规范的,并且搜索JavaScript错误处理/异常最佳实践也没有结果,因此我认为尝试征求一些简明的想法可能会有所帮助,既为了我自己的理解,也为了未来的搜索者。也许这是一个不太可能规定最佳实践的主题,因为每种情况都非常独特? - Joshua Cody
1
每一段代码都应该被包裹在try/catch中吗?当然不是。有很多你知道永远都能正常工作的代码(当然,假设你进行了测试,但try/catch的目的并不是为了捕获或掩盖编码错误)。只有将可能由于其控制范围之外的某些原因而失败的代码进行包装,通常是像资源访问等这样的东西。注意:一些可能会失败的事情已经内置了错误处理,例如,如果有很多库可以处理跨浏览器问题并允许您指定错误处理程序函数,那么我就不必从头开始编写Ajax。 - nnnnnn
1
这是一个很好的问题,Josh,加一。有很多关于语法的建议,但正如你所说,那是容易的部分。在这个问题的答案中提到了它(https://dev59.com/G3E85IYBdhLWcg3wViA4),解释了异常在JS中不常用的原因。 - whitneyland
5个回答

68
可以在这里找到一组关于企业级JavaScript错误处理的幻灯片,非常有趣。 简而言之,它总结了以下几点:
  1. 假设您的代码会失败
  2. 将错误记录到服务器上
  3. 由您而不是浏览器处理错误
  4. 识别可能出现错误的地方
  5. 抛出自己的错误
  6. 区分致命和非致命错误
  7. 提供调试模式
这些幻灯片详细阐述了每个方面,并很可能给您提供一些指导。请注意,上述演示文稿可以在这里找到。

26
Devhands的链接已经失效。 - Ryan Gates
11
对于那些在2017年阅读这篇文章的人,我认为您从这些幻灯片中得到的价值不会很大 - 这份摘要已经给了您90%的信息。但这仍是有价值的信息。干杯! - Philippe Hebert

30
尼古拉斯·扎卡斯在2008年Ajax Experience上做了一个关于企业级错误处理的演讲(幻灯片),他提出了类似这样的东西:
function log(sev,msg) {
    var img = new Image();
    img.src = "log.php?sev=" +
        encodeURIComponent(sev) +
        "&msg=" + encodeURIComponent(msg);
}

// usage
log(1, "Something bad happened.")

// Auto-log uncaught JS errors
window.onerror = function(msg, url, line) {
    log(1, msg);
    return true;
}

一年后,Nicholas Zakas在他的博客上发布了一篇更新,其中包括一个巧妙的模式,可以在生产环境中自动注入错误处理代码(使用面向方面的编程)。

当你开始记录 window.error 调用时,你会注意到两件事情:

  1. 如果您的网站相当复杂,您将记录大量的错误信息。
  2. 你会看到一堆无用的 "window.error in undefined:0" 消息。

减少日志条目的洪流很简单,只需在记录到服务器之前测试严重性和/或随机数即可:

function log(sev,msg) {
    if (Math.random() > 0.1) return; // only log some errors

    var img = new Image();
    img.src = "log.php?sev=" +
        encodeURIComponent(sev) +
        "&msg=" + encodeURIComponent(msg);
}

处理无用的 window.error in undefined:0 错误取决于您的站点架构,但可以尝试识别所有 Ajax 调用,并在出现错误时抛出异常(可能使用 stacktrace.js 返回堆栈跟踪)。

76
我知道这是一个老问题,但建议随意忽略某些错误是我听过的最糟糕的想法之一。 - jbabey
35
对于小网站而言,你是正确的,但如果你运营一个有数十万或数百万用户的大型网站,就不需要向服务器(或互联网)发送冗余的日志记录请求。在足够大的系统中,每个真正的错误每天都会发生数万次,因此这种限制方式非常有效。这个想法实际上已经在Facebook上实现了。 - Jens Roland
1
在调试模式下记录错误与限制生产错误报告同样重要,因此需要一种解决方案来管理日志记录阈值的限制。 - frattaro
2
@NickBull,我在2011-2012年期间反向工程了一堆Facebook的JavaScript模块;那就是我找到它的地方。 - Jens Roland
1
@JensRoland +1,太棒了!有时候即使是最大的公司在生产中也可能会使用小成本代码,这真是让人惊讶。 - Nick Bull
显示剩余6条评论

8
IHMO,你应该像其他几种语言一样(AFAIK:Python,Java)在javascript中使用错误处理。
为了更好的可读性(可能会有更好的性能,尽管我不确定它是否真的有很大的影响),你应该主要在以下情况下使用try/catch块:
- 你想要包装的代码部分是整个算法的关键部分。如果它失败了,可能会: - 在代码的下一部分创建错误(例如因为缺少变量...) - 使页面看起来与预期不同(对内容或css的影响) - 使结果对用户显示异常(对代码行为的影响) - 你知道你正在编写的代码与每个浏览器都不兼容。 - 你计划代码可能会失败(因为没有其他方法来检查应该通过if...then...块工作的方式)。 - 当你想要调试而不打扰最终用户时
最终,javascript专家可能有其他要给出的要点。
祝好,
Max

2
你想要包装的代码部分是整个算法的关键部分 - 可能取决于你如何处理失败。如果你知道在失败后没有继续执行算法的方法,最好将整个算法包装在try/catch中,因为如果你的try/catch被嵌套在循环中(例如),那么它会更加影响性能。另一方面,如果你可以对异常采取一些行动并继续执行算法,那么你将需要一个更精细的try/catch设置。 - nnnnnn

6
除了其他回答之外:一个重要的事情是使用JavaScript错误对象和window.onerror函数参数中可用的上下文数据。
例如堆栈跟踪(errorObject.stack)、文件名、行号和列号等。 请注意,每个浏览器都有一些差异...所以尽力获取良好的错误。
甚至控制台对象本身也可能存在问题。 我使用受此代码启发的自定义window.onerror函数和一个特殊的函数来跟踪任何给定的标准错误对象,灵感来自于这段代码
另一个好的点是在堆栈跟踪附近包含您的Web应用程序的版本(以便快速安全地复制和粘贴)。在开发模式下,您还可以更积极地显示错误(警报...),因为开发人员不会不断监视浏览器控制台,可能看不到某些问题。
另外,避免使用throw 'My message',改用throw new Error('My message'),你甚至可以自定义错误,请参阅this article
始终为错误添加一些上下文(版本、对象ID、一些自定义消息等),并确保区分外部错误(某些外部数据或情况导致系统失败)和内部错误/断言(您自己的系统出错),请阅读有关“按合同设计”的内容。
这里是一个指南
此外,考虑使用通用错误处理程序,如拦截器库和框架:

0

我为此创建了脚本。它会阻止除允许列表中提到的项目之外的所有控制台命令,或者阻止阻止列表中的所有内容。即使有彩色控制台日志,也能很好地工作。

https://github.com/iiic/consoleFilter.js


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接