如何调试一个Node.js应用程序:提示,技巧和工具

克雷格的盾牌
分享

软件开发是复杂的,在某些时候,你的Node.js应用程序会失败。如果你幸运的,您的代码将崩溃,并显示明显的错误消息。如果不走运,应用程序将继续运行,但不会生成您期望的结果。如果您真的很不幸,在第一个用户发现灾难性的磁盘擦除错误之前,一切都可以正常工作。

什么是调试?

调试是修复软件缺陷的黑魔法。修复一个错误通常很容易——一个修正过的字符或额外的代码行就能解决问题。找到错误是另一回事,开发人员可能会花很多时间试图找到问题的根源。幸运的是,Node.js有一些很好的工具来帮助跟踪错误。

术语

调试有自己的晦涩术语,包括以下内容:

术语 解释
断点 调试器停止程序以检查其状态的点
调试器 提供调试功能的工具,如逐行运行代码以检查内部变量状态
功能 正如声明中所说:“这不是一个bug,这是一个功能”。所有开发者在他们职业生涯的某个阶段都会这么说
频率 bug发生的频率和条件是什么
不管用 最常见但最没用的错误报告
记录点 发送给调试器的一条指令,用于显示执行过程中某个时点上变量的值
日志记录 将运行时信息输出到控制台或文件
逻辑错误 程序可以工作,但没有按照预期的方式工作
优先级 在计划更新列表中分配bug的位置
竞态条件 难以追踪的bug依赖于不可控事件的顺序或时间
重构 重写代码以提高可读性和维护
回归 以前修复的错误可能由于其他更新而重新出现
相关的 与另一种昆虫相似或相关的昆虫
繁殖 导致错误所需的步骤
RTFM错误 用户不称职伪装成错误报告,通常后面跟着一个响应“Read The翻转手册》
进入 在调试器中逐行运行代码时,进入被调用的函数
走出 逐行运行时,完成当前函数的执行并返回调用代码
跨过 逐行运行时,完成命令的执行,而不进入它调用的函数
严重程度 bug对系统的影响。例如,数据丢失通常被认为比UI问题更有问题,除非发生的频率非常低
堆栈跟踪 错误发生前调用的所有函数的历史列表
语法错误 印刷错误,例如console.lug ()
用户错误 由用户而不是应用程序引起的错误,但仍然可能导致更新,这取决于该人的资历
要在调试器执行期间检查的变量
监视点 与断点类似,不同的是,当变量被设置为特定值时,程序将停止

如何避免bug

在测试应用程序之前,通常可以防止出现错误。

使用好的代码编辑器

一个好的代码编辑器将提供许多功能,包括行号、自动补全、颜色编码、括号匹配、格式化、自动缩进、变量重命名、代码段重用、对象检查、函数导航、参数提示、重构、不可达代码检测、建议、类型检查等等。

Node.js开发人员被免费的编辑器宠坏了,比如VS代码原子,括号,以及大量的商业替代品。

使用代码检查器

在保存和测试代码之前,linter可以报告代码错误,例如语法错误、糟糕的缩进、未声明的变量和不匹配的括号。JavaScript和Node.js的流行选项包括ESLintJSLint,JSHint

这些通常被安装为全局Node.js模块,这样你就可以从命令行运行检查:

eslint myfile.js

然而,大多数linter都有代码编辑器插件,例如ESLint for VS Code而且Atom的linter-eslint当你输入时检查你的代码:

ESLint for VS Code

使用源代码控制

一个源代码控制系统,如Git可以帮助保护您的代码和管理修订。更容易发现bug是何时何地被引入的,以及谁应该受到责备!在线存储库,例如GitHub而且Bitbucket都提供免费空间和管理工具。

采用问题跟踪系统

如果没有人知道一个漏洞是否存在?问题跟踪系统用于报告错误、查找重复、记录复制步骤、确定严重程度、计算优先级、分配开发人员、记录讨论以及跟踪任何修复的进度。

在线源代码存储库通常提供基本的问题跟踪,但是专用的解决方案可能适用于较大的团队和项目。

使用测试驱动开发

测试驱动开发(TDD)是一种开发过程,它鼓励开发人员在编写函数之前编写测试函数操作的代码,例如,当函数Y被传递输入Z时是否返回X

可以在开发代码时运行测试,以证明函数可以工作,并在进行进一步更改时发现任何问题。也就是说,你的测试也可能有bug…

一步

人们很容易熬夜,徒劳地试图找到一个讨厌的bug的源头。不喜欢。走开,做点别的事。你的大脑会下意识地解决问题,并在凌晨4点把你叫醒。即使这种情况没有发生,新鲜的眼睛也会发现明显缺失的分号。

Node.js调试:环境变量

环境变量可用于控制Node.js应用程序设置。最常见的是NODE_ENV,通常设置为发展当调试。

Linux/macOS下支持设置环境变量:

NODE_ENV发展

窗户cmd

NODE_ENV发展

或者Windows Powershell:

env美元: NODE_ENV<年代pan class="token operator">=“发展”

在内部,应用程序将启用进一步的调试特性和消息。例如:

// NODE_ENV设置为“development”?常量DEVMODE过程<年代pan class="token punctuation">.envNODE_ENV= = =“发展”如果DEVMODE{控制台日志应用程序以开发模式在端口${port}上启动

NODE_DEBUG使用Node.js启用调试消息util.debuglog(见下文),但也可以参考您的主要模块和框架的文档,以发现更多的选项。

注意,环境变量也可以保存到.env文件。例如:

NODE_ENV=development NODE_LOG=./log/debug.log SERVER_PORT=3000 DB_HOST=localhost DB_NAME=mydatabase .log

然后使用dotenv模块

需要“dotenv”配置

Node.js调试:命令行选项

各种各样的命令行选项可以传递给节点运行时启动应用程序。其中最有用的是——trace-warnings,它为进程警告(包括弃用)输出堆栈跟踪。

可以设置任意数量的选项,包括:

  • ——enable-source-maps:启用源映射(实验性)
  • ——throw-deprecation:当使用已弃用的特性时抛出错误
  • ——检查:激活V8检查器(见下文)

作为一个例子,让我们尝试记录日志加密模块DEFAULT_ENCODING财产,在Node v10中已弃用:

常量加密<年代pan class="token operator">=需要“密码”函数酒吧{控制台日志加密<年代pan class="token punctuation">.DEFAULT_ENCODING函数喷火{酒吧喷火

现在用以下命令运行它:

节点index.js

然后我们会看到:

buffer (node:7405) [DEP0091] DeprecationWarning: crypto.使用实例DEFAULT_ENCODING已弃用。

然而,我们也可以这样做:

Node——trace-warnings index.js

这会产生以下结果:

buffer (node:7502) [DEP0091] DeprecationWarning: crypto. [DEP0091] DeprecationWarning: crypto.]DEFAULT_ENCODING已弃用。at bar (/home/Desktop/index.js:4:22) at foo (/home/Desktop/index.js:8:3) at Object。<匿名> (/home/Desktop/index.js:11:1)_compile (internal/modules/cjs/loader.js:1151:30) at Object.Module._extensions. js (internal/modules/cjs/loader.js:1171:10) at Module. Module. jsload (internal/modules/cjs/loader.js:1000:32)_load (internal/modules/cjs/loader.js:899:14)executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12) at internal/main/run_main_module.js:17:47

这告诉我们,弃用警告来自第4行代码console.log语句),当酒吧函数了。的酒吧函数调用喷火函数在第8行和喷火函数在脚本的第11行被调用。

注意,同样的选项也可以传递给nodemon

控制台的调试

调试应用程序最简单的方法之一是在执行时将值输出到控制台:

控制台日志myVariable<年代pan class="token punctuation">)

很少有开发人员钻研这个简单的调试命令之外的东西,但是他们错过了更多的可能性,包括:

控制台方法 描述
. log(味精) 向控制台输出一条消息
.dir (obj,选择) 使用util.inspect漂亮地打印对象和属性
.table (obj) 以表格格式输出对象数组
. error(味精) 输出错误消息
.count(标签) 一个已命名的计数器,报告该行已执行的次数
.countReset(标签) 重置一个命名计数器
.group(标签) 缩进一组日志消息
.groupEnd(标签) 结束缩进的组
.time(标签) 启动一个计时器来计算操作的持续时间
.timeLog((标签) 报告计时器启动后经过的时间
.timeEnd(标签) 停止计时器并报告总持续时间
.trace () 输出堆栈跟踪(所有调用函数的列表)
.clear () 清除控制台

console.log ()接受逗号分隔值的列表。例如:

x<年代pan class="token operator">=123控制台日志“x:“x<年代pan class="token punctuation">)// x: 123

然而,ES6解构可以用更少的输入工作提供类似的输出:

控制台日志{x<年代pan class="token punctuation">}// {x: 123}

较大的对象可以使用以下命令输出为压缩字符串:

控制台日志JSONstringifyobj<年代pan class="token punctuation">)

util.inspect将对象格式化为更容易阅读,但是console.dir ()为你做艰苦的工作。

node . jsutil.debuglog

在node . js跑龙套模块提供了内置的debuglog方法,该方法有条件地将消息写入STDERR

常量跑龙套<年代pan class="token operator">=需要“跑龙套”常量debuglog<年代pan class="token operator">=跑龙套<年代pan class="token punctuation">.debuglog“myapp”debuglogmyapp调试信息[%d]123

NODE_DEBUG环境变量设置为myapp(或通配符,如我*),消息显示在控制台中:

NODE_DEBUGmyapp节点索引<年代pan class="token number">9876: myapp调试消息<年代pan class="token punctuation">[123]

在这里,9876是Node.js进程ID。

默认情况下,util.debuglog是沉默。如果运行上面的脚本而不设置NODE_DEBUG变量时,将不会向控制台输出任何内容。这允许您在代码中留下有用的调试日志,而不会使控制台变得混乱。

使用日志模块调试

如果您需要更复杂的消息传递级别、详细程度、排序、文件输出、概要分析等选项,则可以使用第三方日志记录模块。常见的选项包括:

Node.js V8检查器

在以下部分中,pagehit项目开发的其他教程用于说明调试概念。你可以用以下方法下载:

git克隆https://github.com/site必威西盟体育网页登录point-editors/pagehit-ram

也可以使用自己的代码。

Node.js是V8 JavaScript引擎的包装器,它包含自己的引擎检查器和调试客户端.首先,使用检查论点(不要与之混淆——检查)以启动应用程序:

节点inspect ./index.js

调试器将在第一行处暂停并显示调试>提示:

<调试器监听ws://127.0.0.1:9229/6f38abc1-8568-4035-a5d2-dee6cbbf7e44<年代pan class="token operator"><如需帮助,请参见:https://nodejs.org/en/docs/inspector<年代pan class="token operator"><调试器。启动时中断<年代pan class="token keyword">在index.js: 7<年代pan class="token number">5常量<年代pan class="token number">6//默认HTTP端口<年代pan class="token operator">>7港口<年代pan class="token operator">=3000,<年代pan class="token number">89// Node.js模块调试<年代pan class="token operator">>

你可以输入:

  • c:继续执行
  • 下一个n:执行下一条命令
  • 一步年代:进入一个被调用的函数
  • o:退出函数并返回调用函数的命令
  • 暂停:暂停运行代码

其他选项包括:

如果这听起来非常笨拙,它是.只有在绝对没有其他选择,感觉特别受虐,并且没有使用Windows(这通常是有问题的)时,才使用内置的调试客户端。

使用Chrome调试Node.js

Node.js检查器(没有调试器客户端)是用——检查国旗:

Node——inspect ./index.js

注意:nodemon可以用来代替节点如果有必要的话)。

这将启动调试器监听127.0.0.1:9229,任何本地调试客户端都可以附加到:

调试器监听ws://127.0.0.1:9229/20ac75ae-90c5-4db6-af6b-d9d74592572f

如果你在其他设备或Docker容器上运行Node.js应用程序,请确保端口9229是可访问的,并授予远程访问使用:

节点——检查<年代pan class="token operator">=0.0.0.0:9229。/ index.js

或者,您可以使用——inspect-brk在第一个语句上设置断点,以便立即暂停应用程序。

打开Chrome浏览器,输入chrome: / /检查在地址栏。

Chrome检查

注意:如果Node.js应用程序不显示为<年代trong>遥远的目标,确保<年代trong>发现网络目标选中,然后单击<年代trong>配置,添加应用程序所在设备的IP地址和端口。

点击目标的<年代trong>检查链接来启动DevTools。任何有浏览器调试经验的人都会立即熟悉它。

Chrome DevTools

的<年代trong>+添加文件夹到工作区link允许你选择Node.js文件在你的系统中的位置,这样就更容易加载其他模块并进行更改。

单击任何行号设置一个断点,用绿色标记表示,当到达该代码时停止执行:

Chrome DevTools断点

变量可以添加到<年代trong>看面板上的<年代trong>+图标,并输入他们的名字。它们的值在执行暂停时显示。

的<年代trong>调用堆栈窗格显示了为了到达这一点调用了哪些函数。

的<年代trong>范围窗格显示所有可用的本地和全局变量的状态。

的<年代trong>断点窗格显示所有断点的列表,并允许启用或禁用它们。

上面的图标<年代trong>调试器停了下来消息可用于恢复执行、跨进、跨进、跨出、跨出、禁用所有断点和暂停异常。

用VS Code调试Node.js

当你在本地系统上运行Node.js应用程序时,无需任何配置就可以启动Node.js调试。打开起始文件(通常是index.js),激活<年代trong>运行和调试窗格,并单击<年代trong>运行和调试Node.js (F5)按钮。

VS代码调试器

调试屏幕类似于Chrome DevTools<年代trong>变量,<年代trong>看,<年代trong>调用堆栈,<年代trong>加载脚本,<年代trong>断点列表。

VS代码断点

可以通过单击行号旁边的槽来设置断点。您也可以右键单击。

VS Code断点选项

用这个右键单击,你可以设置如下:

  1. 一个标准断点。

  2. 条件断点,在满足条件时停止—例如,数> 3

  3. 一个对数点,有效的console.log ()没有代码!任何字符串都可以用花括号表示的表达式输入-例如,{数}属性的值变量。

    VS代码日志点

注:别忘了打返回为VS Code创建条件断点或日志点。

顶部的调试图标栏可用于恢复执行、跳过、进入、退出、重新启动或停止应用程序和调试。相同的选项也可从<年代trong>调试菜单上的项目。

有关更多信息,请参阅在Visual Studio代码中调试

高级调试配置

在调试远程服务或需要使用不同的启动选项时,需要进一步配置。VS Code将启动配置存储在launch.json.vscode项目中的文件夹。要生成或编辑文件,请单击页面右上方的齿轮图标<年代trong>运行和调试窗格。

VS代码启动配置

属性中可以添加任意数量的配置设置配置数组中。单击<年代trong>添加配置按钮,选择一个选项。VS Code可以:

  1. 发射一个使用Node.js本身的进程,或者
  2. 附加到Node.js检查器进程,可能运行在远程机器或Docker容器上

在上面的示例中,定义了一个单独的Nodemon启动配置。保存launch.json中,选择nodemon的顶部的下拉列表中<年代trong>运行和调试窗格,并单击绿色的开始图标。

VS代码启动

有关详细信息,请参见启动配置

其他Node.js调试工具

Node.js调试指南为其他ide和编辑器提供建议,包括Visual Studio, JetBrains, WebStorm, Gitpod和Eclipse。Atom还有一个node-debug扩展。

ndb提供了一个改进的调试体验具有强大的功能,如附加到子进程和脚本黑盒,因此只显示特定文件夹中的代码。

IBM report-toolkit for Node.js工作时通过分析数据输出节点是由——实验报告选择。

最后,商业服务等LogRocket而且Sentry.io在客户端和服务器中集成您的实时web应用程序,以便在用户遇到错误时记录错误。

得到调试!

Node.js有一系列很棒的调试工具和代码分析器,可以提高应用程序的速度和可靠性。他们是否能引诱你离开console.log ()那是另一回事!

Baidu