在调试应用程序时,总是有一些挑战。Node.js的异步工作流程为这个艰巨的过程增加了一层复杂性。虽然已经对V8引擎进行了一些更新,以便轻松访问异步堆栈跟踪,但大多数时候,我们只是在应用程序的主线程上获得错误,这使得调试有点困难。同样,当我们的Node.js应用程序崩溃时,我们通常需要依靠一些复杂的CLI工具来分析核心转储的情况。
在这篇文章中,我们将看看一些更简单的方法来调试你的Node.js应用程序。
日志
当然,没有日志记录的开发者工具包是不完整的。在本地开发中,我们倾向于将console.log ,但在生产中这并不是一个真正可扩展的策略。你可能需要做一些过滤和清理工作,或者实施一个一致的日志策略,以便从真正的错误中识别出重要的信息。
相反,为了实现一个适当的面向日志的调试策略,请使用像Pino或Winston这样的日志工具。这些将允许你设置日志级别(INFO,WARN,ERROR),允许你在本地打印冗长的日志信息,只为生产打印严重的信息。你还可以将这些日志流向聚合器,或其他终端,如LogStash、Papertrail,甚至Slack。
与Node Inspect和Chrome DevTools合作
日志只能帮助我们了解为什么应用程序没有按照我们预期的方式工作。对于复杂的调试环节,我们希望使用断点来检查我们的代码在执行时的表现。
要做到这一点,我们可以使用Node Inspect。Node Inspect是Node.js自带的一个调试工具。它实际上只是Chrome DevTools在程序中的一个实现,让你添加断点,控制逐步执行,查看变量,并跟踪调用栈。
有几种方法可以启动Node Inspect,但最简单的也许是用--inspect-brk 标志来调用你的Node.js应用程序。
$ node --inspect-brk $your_script_name

启动你的程序后,在你的Chrome浏览器中前往chrome://inspect URL,进入Chrome DevTools。有了Chrome DevTools,你就有了在浏览器中调试JavaScript时通常所期望的所有功能。其中一个比较好的工具是检查内存的能力。你可以拍摄堆快照和剖析内存使用情况,以了解内存的分配情况,并有可能堵塞任何内存泄漏。
使用支持的IDE
许多现代IDE也支持调试Node应用程序,而不是以某种方式启动你的程序。除了具有Chrome DevTools中的许多功能外,它们还带来了自己的功能,如创建日志点,并允许你创建多个调试配置文件。请查看Node.js的检查员客户端指南,了解有关这些IDE的更多信息。
使用NDB

另一个选择是安装NDB,一个独立的Node.js调试器。它利用了浏览器中可用的相同的DevTools,只是作为一个独立的本地调试器。它也有一些DevTools中没有的额外功能。它支持就地编辑,这意味着你可以对你的代码进行修改,并让调试器平台直接支持更新的逻辑。这对于进行快速迭代非常有用。
死后调试
假设你的应用程序由于一个灾难性的错误而崩溃,比如内存访问错误。这种情况可能很少,但确实发生了,特别是当你的应用程序依赖于本地代码时。
为了调查这类问题,你可以使用llnode。当你的程序崩溃时,llnode ,通过将它们映射到C/C++端的对象上,可以用来检查JavaScript堆栈框架和对象。为了使用它,你首先需要一个你的程序的核心转储。要做到这一点,你需要使用process.abort ,而不是process.exit ,来关闭你代码中的进程。当你使用process.abort ,Node进程会在退出时生成一个核心转储文件。
为了更好地了解llnode ,这里有一段视频,演示了它的一些功能。
有用的Node模块
除了上述所有这些,还有一些第三方软件包,我们可以推荐给你,以便进一步调试。
调试
其中第一个被称为,简单地说,debug。有了debug,你可以为你的日志信息指定一个特定的命名空间,基于一个函数名称或整个模块。然后,你可以通过一个特定的环境变量有选择地选择哪些信息被打印到控制台。
例如,这里有一个Node.js服务器,它正在记录来自整个应用程序和中间件堆栈的几个消息,如sequelize ,express:application ,和express:router 。

如果我们将DEBUG 环境变量设置为express:router ,并启动同一程序,则只显示标记为express:router 的消息。

通过这种方式过滤消息,我们可以在不需要大幅度改变代码的记录的情况下,对应用程序的单个部分的行为进行精确定位。
追踪和澄清
trace clarify ,通过提供正在调用的异步方法的更详细的信息来增强你的异步堆栈跟踪,这是Node.js默认不提供的路线图。通过删除堆栈跟踪中所有特定于Node.js内部的信息来帮助。这使你能够专注于特定于你的应用程序的函数调用。
这两个模块都不建议在生产中运行。你应该只在本地开发环境中调试问题时启用它们。