Node.js 深度调试指南

在 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 启动

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

Chrome DevTools

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

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

运行中程序调试

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

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

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

kill -SIGUSR1 34943 复制代码

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

node -e 'process._debugProcess(30464)'

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

VS Code 调试

快速调试

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

使用配置调试

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

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

{
   "version": "0.2.0",
   "configurations": [
     {
       "type": "node",
       "request": "launch",
       "name": "启动程序",
       "skipFiles": ["<node_internals>/**"],
       "program": "${workspaceFolder}/index.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 提供了好用的调试小工具 - 日志点,日志点是断点的一种变体,它不 "中断 "进入调试器,而是将一条消息记录到控制台,日志点对于在调试不能暂停或停止的生产服务器时注入日志特别有用。

NPM 脚本调试

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

"scripts": {
     "debug": "node --inspect server.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 调试功能,并在本地连接上远程的调试端口进行调试。

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 选项导致的。

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

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

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

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

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

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

结语

大家有什么要说的,欢迎在评论区留言

对了,小编为大家准备了一套2020最新的web前端资料,需要点击下方链接获取方式

1、点赞+评论(勾选“同时转发”)

学习前端,你掌握这些。二线也能轻松拿8K以上

参考文献

Debugging - Getting Started | Node.js

Debug Node.js Apps using Visual Studio Code

(0)

相关推荐

  • Vue2+Koa2+Typescript前后端框架教程--02后端KOA2框架自动重启编译服务(nodemon)

    上一篇讲完搭建Typescritp版的Koa框架后,F5运行服务端,页面进行正常显示服务. 今天要分享的是,如果要修改服务端代码,如果让编译服务自动重启,免去手动结束服务再重启的过程. 自动重启服务需 ...

  • 方便快捷的调试 Node.js 程序

    疯狂的技术宅 前端先锋 在调试程序时总是会遇到各种挑战.Node.js 的异步工作流为这一艰巨的过程增加了额外的复杂性.尽管 V8 引擎为了方便访问异步栈跟踪进行了一些更新,但是在很多数情况下,我们只 ...

  • 写 Node.js 代码,从学会调试开始

    张挺 前端试炼 1周前 在纷繁复杂的代码世界中,出错是难免的,也许在传统的前端代码中,你习惯于 console 来排查问题,这是不合理的,在现代的社会下,调试代码是你最快找到问题的方法. 这篇文章就是 ...

  • Node.js 入门你需要知道的 10 个问题

    前端技术优选 以下文章来源于Nodejs技术栈 ,作者五月君 本文为您分享「Node.js 入门你需要知道的 10 个问题」这些问题可能也是面试中会被问到的,当然问题不仅仅是这 10 道,因此,最近开 ...

  • 使用 VS Code 调试 Node.js 的超简单方法

    前端技术优选 以下文章来源于掘金开发者社区 ,作者iceytea 掘金开发者社区掘金,一个帮助开发者成长的技术社区 原文地址:The Absolute Easiest Way to Debug Nod ...

  • Node.js 安全指南

    当项目周期快结束时,开发人员会越来越关注应用的"安全性"问题.一个安全的应用程序并不是一种奢侈,而是必要的.你应该在开发的每个阶段都考虑应用程序的安全性,例如系统架构.设计.编码, ...

  • 快上车!使用 Node.js 搭建一个 API 网关

    编程微刊 1周前 以下文章来源于程序员成长指北 ,作者koala 程序员成长指北专注 Node.js 技术栈分享,从 前端 到 Node.js 再到 后端数据库,祝您成为优秀的高级 Node.js 全 ...

  • 简析 Node.js 特点与应用场景(让你更了解它)

    前端技术优选 今天 以下文章来源于程序员成长指北 ,作者koala 如果你有一定的前端基础,比如 HTML.CSS.JavaScript.jQuery:那么,Node.js 能让你以最低的成本快速过渡 ...

  • JavaScript 事件循环:从起源到浏览器再到 Node.js

    冰森 前端技术优选 今天 很多文章都在讨论事件循环 (Event Loop) 是什么,而几乎没有人讨论为什么 JavaScript 中会有事件循环.博主认为这是为什么很多人都不能很好理解事件循环的一个 ...

  • 看了就会的 Node.js 三大基础模块常用 API

    技术漫谈 4月11日 以下文章来源于前端试炼 ,作者小炼

  • 字节跳动最爱考的前端面试题:Node.js 基础

    前端技术优选 今天 前几天,跟我一朋友聊天,他现在是阿里的架构师,说:「他们根本不知道,现在的电商大促有多么依赖 Node.js.」 说真的,我倒并不意外.作为一个定位明确的高性能 Web 服务器,N ...