如何用多种工具调试Node.js代码
Node.js是一个JavaScript运行时,基于Google Chrome浏览器中使用的相同V8引擎。它通常用于构建跨平台的服务器端和终端应用程序。Node.js在过去十年中变得越来越流行,因为它易于安装、实用且快速,并允许客户端Web开发人员在其他地方使用他们的技能。
然而,软件开发仍然是一项复杂的任务,你的Node.js代码有时会失败。本教程演示了各种工具来帮助调试应用程序并找出问题的原因。
提示:Deno是一个可选的JavaScript运行时。它类似于Node.js,但更新,并且消除了一些裂缝和不一致。以下工具和信息通常可以应用于Deno应用程序和Node.js
调试概述
设置适当的Node.js环境变量。
使用Node.js命令行选项。
将消息输出到控制台。
使用第三方日志系统
使用V8检查器
用Chrome浏览器调试Node.js代码
条件断点
要点
用VS代码调试Node.js应用程序
VS代码高级调试配置
Node.js的其他调试选项
调试概述
“调试”是修复软件缺陷的各种方法的名称。修复错误通常很简单。查找错误的原因可能要复杂得多,而且需要几个小时。
以下部分描述了您将会遇到的三种常见错误类型。
语法错误
您的代码没有遵循语言规则——例如,当您省略了右括号或拼写错误的语句(如console.lag(x ))时。
一个好的代码编辑器可以通过以下方式帮助发现常见问题:
有效或无效陈述的颜色代码
检查类型变量
自动完成函数和变量名
显示匹配的括号。
自动缩进代码块
检测不可访问的代码。
重构杂乱的函数。
VS Code、Atom等免费编辑器对Node.js、JavaScript、TypeScript(可以转换成JavaScript)提供了很好的支持。在保存和测试代码之前,通常可以找到基本的语法问题。
像ESLint这样的代码也报告语法错误、缩进错误和未声明的变量。ESLint是一个Node.js工具,可以通过以下方式进行全局安装:
npm i eslint -g
您可以使用以下命令从命令行检查JavaScript文件:
eslint mycode.js
…但使用编辑器插件更容易,例如VS代码的ESLint或Atom的linter-eslint,它们会在您键入时自动验证代码:
VS代码中的ESlint
逻辑错误
您的代码可以运行,但不能按预期工作。比如用户请求时没有注销;报告不正确的数字;数据没有完全保存在数据库中;等一下。
逻辑错误可能由以下原因引起:
使用错误的变量。
不正确的条件,例如,if (a > 5)而不是if (a < 5)
未能考虑运算符优先级的计算,例如,1+2*3的结果是7而不是9。
运行时(或执行)错误
只有在执行应用程序时,错误才会变得明显,这通常会导致崩溃。运行时错误可能由以下原因引起:
除以设置为零的变量。
试图访问不存在的数组项目。
尝试写入只读文件。
尽管以下开发技术会有所帮助,但逻辑和运行时错误更难发现:
使用测试驱动开发:TTD鼓励你在开发功能之前编写测试。例如,当z作为参数传递时,x从函数y返回。这些测试在初始开发和后续更新期间运行,以确保代码继续按预期工作。
使用问题跟踪系统:没有什么比一封电子邮件说“你的软件不能运行”更糟糕的了!问题跟踪系统允许您记录特定问题、记录复制步骤、确定优先级、分配开发人员以及跟踪修复进度。
使用源代码控制:像Git这样的源代码控制系统将帮助您备份代码,管理修订,并确定哪里引入了错误。在线存储库,包括Github和Bitbucket,为小型或开源项目提供免费的空房间和工具。
您仍然会遇到Node.js错误,但是下一节描述了定位这个难以捉摸的错误的方法。
设置适当的Node.js环境变量。
在主机操作系统中设置的环境变量可以控制Node.js应用程序和模块设置。最常见的是NODE_ENV,通常在调试时设置为开发,在实时服务器上运行时设置为生产。在macOS或Linux上设置环境变量:
NODE_ENV=development
或者在(经典)Windows命令提示符下:
set NODE_ENV=development
或Windows Powershell:
$env:NODE_ENV=”development”
在流行的Express.js框架中,将NODE_ENV设置为development会禁用模板文件缓存,并输出详细的错误信息,这可能有助于调试。其他模块可以提供类似的功能。您可以在应用程序中添加NODE_ENV条件,例如
// running in development mode?const devMode = (process.env.NODE_ENV !== ‘production’);if (devMode) {console.log(‘application is running in development mode’);}
还可以使用Node的util.debuglog方法有条件地输出错误信息,例如
import { debuglog } from ‘util’;const myappDebug = debuglog(‘myapp’);myappDebug(‘log something’);
当NODE_DEBUG设置为通配符(如myapp或*或my*)时,该应用程序仅输出日志消息。
使用Node.js命令行选项。
该脚本通常以节点名称开头,后跟门户脚本:
node app.js
您还可以设置命令行选项来控制各种运行时方面。用于调试的有用标志包括:
– check语法检查脚本而不执行它。
– trace-warnings在JavaScript承诺未被解析或拒绝时输出堆栈跟踪。
– enable-source-maps-maps在使用诸如TypeScript之类的转换器时显示源映射。
– throw-deprecation在使用不推荐使用的Node.js函数时发出警告。
– redirect-warnings=file = file将警告输出到文件,而不是stderr。
当调用- trace-exit时,输出堆栈跟踪process.exit()。
将消息输出到控制台。
输出控制台消息是调试Node.js应用程序最简单的方法之一:
console.log(`someVariable: ${ someVariable }`);
很少有开发人员意识到还有许多其他的控制台方法:
控制台方法描述.log(msg)标准控制台消息.log(‘%j’, obj)将对象输出为紧凑的JSON字符串.dir(obj, opt)漂亮打印对象属性.table(obj)以表格格式输出数组和对象.error(msg)错误信息.count(label)增加一个命名的计数器和输出.countReset(label)重置命名计数器.group(label)缩进一组消息.groupEnd(label)终止一个组.time(label)启动一个命名的计时器.timeLog(label)报告经过的时间.timeEnd(label)停止一个命名的计时器.trace()输出堆栈跟踪(所有函数调用的列表).clear()清除控制台
Console.log()也接受逗号分隔的值列表:
let x = 123;console.log(‘x:’, x);// x: 123
…虽然ES6解构提供了类似的输出,但成本更低:
console.log({ x });// { x: 123 }
console.dir()命令以与util.inspect()相同的方式漂亮地打印出对象属性:
console.dir(myObject, { depth: null, color: true });
控制台争议
一些开发人员声称您不应该使用console.log(),因为:
您正在更改代码,可能会更改某些内容或忘记删除它,并且
当有更好的调试选项时,就没有必要了。
不要相信任何声称没用过console.log()的人!录音又快又脏,但每个人在某个时候都会用到。使用任何你喜欢的工具或技术。纠正错误比你发现错误的方式更重要。
使用第三方日志系统
第三方日志系统提供了更复杂的功能,如消息交付级别、详细级别、排序、文件输出、分析、报告等。流行的解决方案包括内阁,loglevel,摩根,皮诺,signale,故事板,追踪器和温斯顿。
使用V8检查器
V8 JavaScript引擎提供了一个可以在Node.js中使用的调试客户端。例如,使用node check来启动应用程序
node inspect app.js
在第一行,调试器暂停并显示debug >提示符:
$ node inspect .mycode.js< Debugger listening on ws://127.0.0.1:9229/143e23fb< For help, see: https://nodejs.org/en/docs/inspector
输入help查看命令列表。您可以通过输入以下内容逐步完成应用程序:
Cont或C:继续执行
或者next n:运行下一个命令
或者s:进入被调用的函数。
或者o:跳出函数,返回调用语句。
暂停:暂停正在运行的代码。
Watch (‘myvar ‘):观察变量
SetBreakPoint()或sb():设置断点。
重启:重启脚本
。退出或Ctrl | Cmd+D:退出调试器。
无可否认,这种调试方法既费时又笨拙。只有在没有其他选择的情况下才使用它,例如当您在远程服务器上运行代码并且无法从其他位置连接或安装其他软件时。
用Chrome浏览器调试Node.js代码
使用上面的Node.js check选项启动一个Web套接字服务器,该服务器监听本地主机端口9229。它还启动了基于文本的调试客户端,但它也可以使用图形客户端——如谷歌Chrome内置的浏览器和Chromium、Edge、Opera、Vivaldi和Brave等基于Chrome的客户端。
要调试典型的Web应用程序,请使用–- inspect选项启动它,以启用V8调试器的Web套接字服务器:
node –inspect index.js
注意事项:
Index.js被假定为应用程序的入口脚本。
确保使用- inspect双破折号来确保不启动基于文本的调试器客户端。
如果希望在文件更改时自动重启应用程序,可以使用nodemon而不是node。
默认情况下,调试器只接受来自本地计算机的传入连接。如果您在另一台设备、虚拟机或Docker容器上运行应用程序,请使用:
node –inspect=0.0.0.0:9229 index.js
节点检查选项
也可以用- inspect-brk代替- inspect在第一行停止处理(设置断点),这样就可以从头开始一步步执行代码。
打开基于Chrome的浏览器,并在地址栏中输入chrome://inspect以查看本地和联网设备:
镀铬检查工具
如果Node.js应用程序没有显示为远程目标,那么:
单击打开节点的专用开发工具,并选择地址和端口,或者
选中发现网络目标,单击配置,然后添加运行它的设备的IP地址和端口。
单击目标的inspect链接启动DevTools调试器客户端。任何使用DevTools进行客户端代码调试的人都应该熟悉这一点:
Chrome开发工具
切换到源面板。您可以通过单击Cmd | Ctrl+P打开任何文件,并输入其文件名(例如,index.js)。
但是,将项目文件夹添加到工作区更容易。这允许你直接从DevTools加载、编辑和保存文件(你是否认为这是一个好主意是另一回事!)
单击+将文件夹添加到工作区。
选择Node.js项目的位置。
单击“同意”以允许文件更改。
现在,您可以从左侧目录树中加载文件:
Chrome DevTools源代码面板
单击任意行号设置由蓝色标记指示的断点。
调试基于断点。指定这些调试器应该在哪里暂停程序执行,并显示程序的当前状态(变量、调用堆栈等。)
您可以在用户界面中定义任意数量的断点。另一种选择是放置一个调试器;在代码中声明它,并在附加调试器时停止。
加载并使用Web应用程序到达设置断点的语句。在这里的例子中,http://localhost:3000/在任何浏览器中打开,DevTools将在第44行停止执行:
铬断点
右侧面板显示:
一排操作图标(见下图)。
“监视”窗格允许您通过单击+图标并输入变量名来监视变量。
“断点”窗格显示所有断点的列表,并允许启用或禁用它们。
范围窗格显示所有局部、模块和全局变量的状态。您将最经常检查此窗格。
“调用堆栈”窗格显示了为此而调用的函数的层次结构。
断点暂停上方显示一行操作图标:
Chrome断点图标
从左到右,他们执行以下操作:
继续执行:继续处理,直到下一个断点。
单步执行:执行下一个命令,但是停留在当前代码块中——不要跳到它调用的任何函数
步入:执行下一个命令,根据需要跳转到任何功能。
步出:继续处理,直到函数结束,并返回调用命令。
Step:类似于step into,只是它不跳转到异步函数。
停用所有断点
异常时暂停:发生错误时停止处理。
条件断点
有时候对断点有更多的控制是必要的。假设您有一个完成1000次迭代的循环,但是您只对最后一次迭代的状态感兴趣:
for (let i = 0; i < 1000; i++) {// set breakpoint here}
而不是点击恢复执行999次,右击该行,选择添加条件断点,然后输入一个条件,比如i = 999:
Chrome条件断点
Chrome用黄色而不是蓝色显示条件断点。在这种情况下,断点仅在循环的最后一次迭代时触发。
要点
日志可以有效实现console.log(),无需任何代码!代码执行任何一行,都可以输出一个表达式,但不会停止处理,这和断点不同。
要添加日志点,请右键单击任意行,选择添加日志点,然后输入表达式,如“循环计数器I”,I:
铬记录点
在上面的例子中,DevTools控制台输出循环计数器i: 0到循环计数器i: 999。
用VS代码调试Node.js应用程序
VS Code或Visual Studio Code是微软的免费代码编辑器,非常受Web开发人员的欢迎。该应用程序可用于Windows、macOS和Linux,是在电子框架中利用Web技术开发的。
VS代码支持Node.js,并且有一个内置的调试客户端。大多数应用程序不需要任何配置就可以调试;编辑器将自动启动调试服务器和客户端。
打开文件(例如index.js),激活“运行和调试”窗格,单击“运行和调试”按钮,然后选择Node.js环境。单击任一行激活显示为红色圆圈图标的断点。然后,像以前一样在浏览器中打开应用程序——vs code在到达断点时停止执行:
VS代码断点
“变量”、“观察”、“调用堆栈”和“断点”窗格与Chrome DevTools中显示的类似。“已加载的脚本”窗格显示已加载的脚本,尽管许多脚本在Node.js内部
图标工具栏允许您:
继续执行:继续处理,直到下一个断点。
单步执行:执行下一个命令,但是停留在当前函数中——不要跳到它调用的任何函数
单步执行:执行下一个命令,并跳转到它调用的任何函数。
步出:继续处理,直到函数结束,并返回调用命令。
重新启动应用程序和调试器
停止应用程序和调试器
与Chrome DevTools一样,您可以右键单击任意行来添加条件断点和日志点。
有关更多信息,请参见Visual Studio代码中的调试。
VS代码高级调试配置
如果您想要在另一个设备、虚拟机上调试代码,或者需要使用其他启动选项(例如nodemon),您可能需要进一步的VS代码配置。
VS代码将调试配置存储在项目目录的launch.json文件中。vscode。打开运行和调试窗格,单击创建一个launch.json文件,然后选择Node.js环境来生成该文件。提供了一个配置示例:
VS代码调试器配置
您可以将任意数量的配置设置定义为“配置”数组中的对象。单击添加配置…并选择适当的选项。
单个Node.js配置可以:
启动流程本身,或者
连接到调试Web套接字服务器,它可能运行在远程机器或Docker容器上。
例如,要定义nodemon配置,请选择Node.js: Nodemon Setup,并在必要时更改“program”条目脚本:
{// custom configuration”version”: “0.2.0”,”configurations”: [{“console”: “integratedTerminal”,”internalConsoleOptions”: “neverOpen”,”name”: “nodemon”,”program”: “${workspaceFolder}/index.js”,”request”: “launch”,”restart”: true,”runtimeExecutable”: “nodemon”,”skipFiles”: [“/**”],”type”: “pwa-node”}]}
保存launch.json文件,nodemon(配置“名称”)出现在“运行和调试”窗格顶部的下拉列表中。单击绿色的run图标开始使用配置,并使用nodemon启动应用程序:
用nodemon调试VS代码
和以前一样,您可以添加断点、条件断点和日志点。主要区别在于,当文件被修改时,nodemon会自动重启您的服务器。
详见VS代码启动配置。
以下VS代码扩展还可以帮助您调试远程或隔离服务器环境中承载的代码:
远程容器:连接到Docker容器中运行的应用程序。
Remote—SSH:连接到远程服务器上运行的应用程序。
Remote—WSL:连接到在Linux的Windows子系统(WSL)上运行的应用程序。
Node.js的其他调试选项
Node.js的调试指南提供了一系列文本编辑器和ide的建议,包括Visual Studio、JetBrains WebStorm、Gitpod和Eclipse。Atom提供了一个节点调试扩展,将Chrome DevTools调试器集成到编辑器中。
一旦你的应用上线,你可以考虑使用商业调试服务,比如LogRocket和Sentry.io,它们可以记录和回放真实用户遇到的客户端和服务器错误。
总结
从历史上看,JavaScript调试一直很困难,但在过去十年中已经有了很大的改进。选择和为其他语言提供的选择一样好——如果不是更好的话。
使用任何实用的工具来定位问题。Console.log()用于快速查找bug,没有任何问题,但对于更复杂的问题,Chrome DevTools或VS代码可能更好。这些工具可以帮助您创建更强大的代码,并且您将花费更少的时间来修复错误。