Node.js 深度调试方法解析


Posted in Javascript onJuly 28, 2020

在 Node.js 项目开发过程中,随着项目的发展,调用关系越来越复杂,调试工具的重要性日益凸显。

Node(v6.3+)集成了方便好用 V8 Inspect 调试器,允许我们通过 Chrome DevTools 进行图形化的调试和性能分析。同时,我们也可以使用 VS Code,Webstorm 等支持的编辑器对 Node.js 程序进行调试。

Node Inspect

要想启动调试器,我们需要在启动 Node.js 应用程序时传入 --inspect 标志,也可以使用该标志提供自定义的端口,例如 --inspect=9222 将会在 9222 端口上接受开发者工具的连接。

一段简单的代码

function log() {
 let a = 1;
 console.log(a);
 a = 2;
 console.log(a);
 }
 ​
 log();

使用 node --inspect 启动

Node.js 深度调试方法解析

这时我们会发现,程序直接执行完成了,没有中断,导致我们无法使用 Chrome DevTools 进行调试。对于这种直接执行的代码,我们可以使用 --inspect-brk 参数,在应用程序代码的第一行终端,然后再进行调试。

Node.js 深度调试方法解析

Chrome DevTools

当开启 Node 调试后,我们可以打开 Chrome,访问 chrome://inspect ,在 Devices 中查找到我们的 Node.js 程序,点击 inspect 打开调试面板进行操作

Node.js 深度调试方法解析

在调试工具窗口,我们可以设置断点,运行程序进行调试

Node.js 深度调试方法解析

运行中程序调试

在某些情况下,我们可以需要对正在运行的 Node.js 程序进行调试,比如 Express Web 服务。我们不可能停止服务,再以 --inspect 运行调试。

对于这种情况,我们可以先获取服务的进程 Id

Node.js 深度调试方法解析

向脚本进程发送 SIGUSR1 信号,就可以建立调试连接

kill -SIGUSR1 34943
复制代码

Node.js 深度调试方法解析

在 Windows 平台下,可以使用下面的命令

node -e 'process._debugProcess(30464)'

需要注意的是:这种调试任然会中断服务进程的执行。

VS Code 调试

快速调试

对于简单的应用程序,可以打开文件,按 F5 并选择调试类型为 Node,即可进行调试

Node.js 深度调试方法解析

使用配置调试

对于大多数的调试场景,更推荐使用配置文件,因为它可以配置并保存调试设置的信息,方便我们下次快速使用。在 VC Code 中,调试配置通常存储在 .vscode 文件夹下的 launch.json 文件中 。可以点击左侧栏目中的调试图标,快速创建 launch.json 文件

Node.js 深度调试方法解析

VS Code 会自动下面类似的 launch.json 调试配置文件,其中 program 代表我们需要调试的文件路径,workspaceFolder 为当前工作区的路径,通常是项目的根目录

{
 "version": "0.2.0",
 "configurations": [
  {
  "type": "node",
  "request": "launch",
  "name": "启动程序",
  "skipFiles": ["<node_internals>/**"],
  "program": "${workspaceFolder}/index.js"
  }
 ]
 }

设置断点,即可启动调试,并在左侧的树视图中看到变量对应的值以及堆栈信息

Node.js 深度调试方法解析

launch.json

launch.json 中有许多不同的属性,支持不同的调试器和调试场景,下面的属性在每个启动配置中是必须的

  • name - 当前调试配置项的名称,可读性要好,区分每个调试配置项
  • type - 用于此启动配置的调试器的类型。每个已安装的调试扩展都引入一种类型:例如node,php,go 等。
  • request - 当前调试项的类型,目前支持 launch 和 attach 两种类型。launch 适合调试未启动的程序,attach 则适合调试已经运行的程序。

一些其他比较有用的选项:

  • program - 启动调试器时要运行的可执行程序或文件
  • args - 传递给程序进行调试的参数
  • env - 调试时的环境变量
  • envFile - 包含环境变量键值对的文件
  • stopOnEntry - 程序启动时立即中断
  • port - 连接到正在运行的调试器的端口
  • runtimeExecutable - 启用调试的可执行 Runtime,默认是 Node

日志点 - Logpoints

VS Code 提供了好用的调试小工具 - 日志点,日志点是断点的一种变体,它不 "中断 "进入调试器,而是将一条消息记录到控制台,日志点对于在调试不能暂停或停止的生产服务器时注入日志特别有用。

Node.js 深度调试方法解析

NPM 脚本调试

除了使用 node 启动 Node.js 项目之外,VS Code 还支持自定义启动程序 runtime,借助这个能力,可以直接使用 NPM 启动调试。如下面,使用 npm run debug 启动调试

{
 "version": "0.2.0",
 "configurations": [
  {
  "type": "node",
  "request": "launch",
  "name": "启动程序",
  "skipFiles": ["<node_internals>/**"],
  "program": "${workspaceFolder}/index.js"
  }
 ]
 }

launch.json

{
 "type": "node",
 "request": "launch",
 "name": "NPM 启动",
 "runtimeExecutable": "npm",
 "runtimeArgs": ["run", "debug"],
 "port": 9229
 }

TypeScript 调试

VS Code 内置的 Node.js 的调试器支持 JavaScript Source Map,可以结合 Source Map 调试转译前的代码,如 TypeScript,压缩混淆的 JavaScript 代码等都可以利用 Source Map 的支持调试源码。

我准备了一个简单的 TS Server Demo,可以直接 Clone 源码本地测试。下面是项目中的 src/index.ts 文件,创建了一个 HTTP Server

import * as http from "http";
 ​
 let reqCount = 1;
 ​
 http
 .createServer((req, res) => {
  const message = `Request Count: ${reqCount}`;
 ​
  res.writeHead(200, { "Content-Type": "text/html" });
 ​
  res.end(`<html><div>${message}</div></html>`);
 ​
  console.log("handled request: " + reqCount++);
 })
 .listen(3000);
 ​
 console.log("server running on port 3000");

创建 tsconfig.json 配置,配置编译生成 Source Map

{
 "compilerOptions": {
  "outDir": "./dist",
  "sourceMap": true
 },
 "include": ["src/**/*"]
 }

使用 tsc 编译一下,生成 JS 代码:dist/index.js,创建调试配置,入口文件为 dist/index.js

{
 "type": "node",
 "request": "launch",
 "name": "Launch Program",
 "program": "${workspaceFolder}/dist/index.js",
 "skipFiles": ["<node_internals>/**"]
 }

然后打断点,启动调试,浏览器访问 http://localhost:3000,即可看到调试进入了 TS 文件

Node.js 深度调试方法解析

远程调试

当我们需要在真实的服务器等远程运行环境调试 Node.js 时,我们可以利用上面提到的方式,在服务器上开启 Node.js 调试功能,并在本地连接上远程的调试端口进行调试。

VS Code 默认支持远程调试,我们需要 launch.json 配置文件中指定远程服务的 IP 地址以及端口,如下所示:

{
 "type": "node",
 "request": "attach",
 "name": "远程调试",
 "address": "IP 地址",
 "port": "9229"
 }

VS Code 会自动加载远程的文件,展示为只读代码供调试使用。

如果想要在调试的过程中编辑源代码,或者更好的调试体验,可以在远程文件夹和本地项目之间设置一个映射。VS Code 提供了 localRoot 和 remoteRoot 属性来映射本地 VS Code 项目和(远程)Node.js 文件夹:

{
 "type": "node",
 "request": "attach",
 "name": "远程调试",
 "address": "IP 地址",
 "port": "9229",
 "localRoot": "${workspaceFolder}/src",
 "remoteRoot": "/var/user/"
 }

在建立映射关系后,即可在本地项目进行断点调试,远程的断点信息会同步到本地项目,使用起来十分方便。

子进程调试

与普通进程调试原理一致,子进程调试时也需要传入 --inspect 参数,这一点需要特别注意,否则无法启动子进程调试。

如下通过子进程启动 Server 的例子:

// fork.js 文件
 const { spawn } = require("child_process");
 ​
 const sp = spawn("node", ["./fork_server.js"]);
 ​
 console.log("父进程 PID", sp.pid);
 ​
 sp.stdout.on("data", (data) => {
 console.log(`stdout: ${data}`);
 });
 ​
 sp.stderr.on("data", (data) => {
 console.error(`stderr: ${data}`);
 });

如果直接使用 node --inspect 启动主进程的话,会发现只显示了主进程的调试端口,这就是因为我们在程序中启动子进程时没有传递 --inspect 选项导致的。

Node.js 深度调试方法解析

这里我们在启动进程时添加上 --inspect 参数,同时注意要指定一个默认 9229 端口之外的端口号,避免调试端口冲突

- const sp = spawn("node", ["./fork_server.js"]);
 + const sp = spawn("node", ["--inspect=9230", "./fork_server.js"]);

再次启动,就能看到两个调试信息输出了

Node.js 深度调试方法解析

当然,怎么能少得了强大的 VS Code 呢。VS Code 的 Node 调试器提供了一种机制,可以追踪所有子进程,并在调试模式下,自动链接进程。可以通过 autoAttachChildProcesses 属性开启此机制:

{
 "type": "node",
 "request": "launch",
 "name": "启动程序",
 "program": "${workspaceFolder}/fork.js",
 "autoAttachChildProcesses": true
 }

启动后,即可对父进程,或子进程进行断点调试,效果如下

Node.js 深度调试方法解析

结语

到此这篇关于Node.js 深度调试方法解析的文章就介绍到这了,更多相关Node.js 深度调方法内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
javascript js cookie的存储,获取和删除
Dec 29 Javascript
利用webqq协议使用python登录qq发消息源码参考
Apr 08 Javascript
解析javascript 数组以及json元素的添加删除
Jun 26 Javascript
jQuery阻止事件冒泡具体实现
Oct 11 Javascript
jquery 模板的应用示例
Nov 12 Javascript
Jquery each方法跳出循环,并获取返回值(实例讲解)
Dec 12 Javascript
javascript中innerText和innerHTML属性用法实例分析
May 13 Javascript
微信小程序 css使用技巧总结
Jan 09 Javascript
vue表单自定义校验规则介绍
Aug 28 Javascript
jQuery创建折叠式菜单
Jun 15 jQuery
vue.js 输入框输入值自动过滤特殊字符替换中问标点操作
Aug 31 Javascript
小程序实现筛子抽奖
May 26 Javascript
vue-列表下详情的展开与折叠案例
Jul 28 #Javascript
js 数组当前行添加数据方法详解
Jul 28 #Javascript
Vue 解决通过this.$refs来获取DOM或者组件报错问题
Jul 28 #Javascript
JS代码简洁方式之函数方法详解
Jul 28 #Javascript
vue 组件之间事件触发($emit)与event Bus($on)的用法说明
Jul 28 #Javascript
JavaScript前端开发时数值运算的小技巧
Jul 28 #Javascript
js实现全选和全不选
Jul 28 #Javascript
You might like
mysql 字段类型说明
2007/04/27 PHP
php5.3 废弃函数小结
2010/05/16 PHP
php使用GD实现颜色渐变实例
2015/06/02 PHP
如何把php5.3版本升级到php5.4或者php5.5
2015/07/31 PHP
大家在抢红包,程序员在研究红包算法
2015/08/31 PHP
简单谈谈 php 文件锁
2017/02/19 PHP
PHP中的正则表达式实例详解
2017/04/25 PHP
Win7环境下Apache连接MySQL提示连接已重置的解决办法
2017/05/09 PHP
Laravel使用scout集成elasticsearch做全文搜索的实现方法
2018/11/30 PHP
一个用javascript写的select支持上下键、首字母筛选以及回车取值的功能
2009/09/09 Javascript
JQuery最佳实践之精妙的自定义事件
2010/08/11 Javascript
javascript 进阶篇1 正则表达式,cookie管理,userData
2012/03/14 Javascript
js 字符串转换成数字的三种方法
2013/03/23 Javascript
JavaScript自定义事件介绍
2013/08/29 Javascript
ajax请求乱码的解决方法(中文乱码)
2014/04/10 Javascript
jQuery中on()方法用法实例
2015/01/19 Javascript
纯JS实现旋转图片3D展示效果
2015/04/12 Javascript
关于JavaScript中事件绑定的方法总结
2016/10/26 Javascript
canvas红包照片实例分享
2017/02/28 Javascript
微信小程序 wx.request方法的异步封装实例详解
2017/05/18 Javascript
基于casperjs和resemble.js实现一个像素对比服务详解
2018/01/10 Javascript
微信小程序实现换肤功能
2018/03/14 Javascript
Vue利用canvas实现移动端手写板的方法
2018/05/03 Javascript
jquery简易手风琴插件的封装
2020/10/13 jQuery
Python中的XML库4Suite Server的介绍
2015/04/14 Python
详解Golang 与python中的字符串反转
2017/07/21 Python
python删除文件夹下相同文件和无法打开的图片
2019/07/16 Python
mac在matplotlib中显示中文的操作方法
2020/03/06 Python
英国排名第一的餐具品牌:Denby Pottery
2019/11/01 全球购物
《乌鸦和狐狸》教学反思
2014/02/08 职场文书
超市开店计划书
2014/04/26 职场文书
汽车维修求职信
2014/06/15 职场文书
2014年节能降耗工作总结
2014/12/11 职场文书
试用期旷工辞退通知书
2015/04/17 职场文书
吧主申请感言怎么写
2015/08/03 职场文书
Sentry的安装、配置、使用教程(Sentry日志手机系统)
2022/07/23 Python