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 八进制转义字符(8进制)
Apr 08 Javascript
js window.open弹出新的网页窗口
Jan 16 Javascript
关于javaScript注册click事件传递参数的不成功问题
Jul 18 Javascript
浅谈页面装载js及性能分析方法
Dec 09 Javascript
Vue中添加过渡效果的方法
Mar 16 Javascript
Vue2组件tree实现无限级树形菜单
Mar 29 Javascript
js登录滑动验证的实现(不滑动无法登陆)
Jan 03 Javascript
利用CDN加速react webpack打包后的文件详解
Feb 22 Javascript
深入浅析AngularJs模版与v-bind
Jul 06 Javascript
JQuery通过后台获取数据遍历到前台的方法
Aug 13 jQuery
JavaScript实现的鼠标跟随特效示例【2则实例】
Dec 22 Javascript
vue与bootstrap实现简单用户信息添加删除功能
Feb 15 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
PHP上传文件时文件过大$_FILES为空的解决方法
2013/11/26 PHP
PHP cURL初始化和执行方法入门级代码
2015/05/28 PHP
微信支付PHP SDK ―― 公众号支付代码详解
2016/09/13 PHP
Laravel 模型关联基础教程详解
2019/09/17 PHP
js监听滚动条滚动事件使得某个标签内容始终位于同一位置
2014/01/24 Javascript
jquery 显示*天*时*分*秒实现时间计时器
2014/05/07 Javascript
node.js中的console.dir方法使用说明
2014/12/10 Javascript
提交按钮的name='submit'引起的js失效问题及原因
2015/02/25 Javascript
分享两款带遮罩的jQuery弹出框
2015/12/30 Javascript
AngularJS+Bootstrap实现多文件上传与管理
2016/11/08 Javascript
jQuery实现简易的输入框字数计数功能示例
2017/01/16 Javascript
jQuery设计思想
2017/03/07 Javascript
AngularJS基于factory创建自定义服务的方法详解
2017/05/25 Javascript
利用Three.js如何实现阴影效果实例代码
2017/09/26 Javascript
Vue响应式原理深入解析及注意事项
2017/12/11 Javascript
利用Blob进行文件上传的完整步骤
2018/08/02 Javascript
antd table按表格里的日期去排序操作
2020/11/17 Javascript
Python通过websocket与js客户端通信示例分析
2014/06/25 Python
python使用pyhook监控键盘并实现切换歌曲的功能
2014/07/18 Python
编写Python脚本来实现最简单的FTP下载的教程
2015/05/04 Python
Python中列表元素转为数字的方法分析
2016/06/14 Python
python 使用get_argument获取url query参数
2017/04/28 Python
用python写一个定时提醒程序的实现代码
2019/07/22 Python
Tory Burch德国官网:美国时尚生活品牌
2018/01/03 全球购物
艺术家策划的室内设计:Curious Egg
2019/03/06 全球购物
绿色环保口号
2014/06/12 职场文书
原料仓仓管员岗位职责
2014/07/08 职场文书
2014最新房贷收入证明范本
2014/09/12 职场文书
购房公证委托书(2014版)
2014/09/12 职场文书
优秀共产党员事迹材料
2014/12/18 职场文书
班主任自我评价范文
2015/03/11 职场文书
win10+anaconda安装yolov5的方法及问题解决方案
2021/04/29 Python
教你怎么用python selenium实现自动化测试
2021/05/27 Python
在 HTML 页面中使用 React的场景分析
2022/01/18 Javascript
Python进程间的通信之语法学习
2022/04/11 Python
在MySQL中你成功的避开了所有索引
2022/04/20 MySQL