【AICon】 如何构建高效的 RAG 系统?RAG 技术在实际应用中遇到的挑战及应对策略?>>> 了解详情
写点什么

关于 Node.js 调试,你需要了解的一切

  • 2023-07-27
    北京
  • 本文字数:6038 字

    阅读完需:约 20 分钟

关于Node.js调试,你需要了解的一切

Node.js 是一种颇具人气的 JavaScript 运行时,与谷歌 Chrome 浏览器一样采用同款 V8 引擎。


Node.js 具备跨平台属性,目前已经成为服务器端 Web 应用程序开发、工具构建和命令行应用程序等领域的主流选项。


但体验过 Node.js 的朋友往往发现,一旦编写代码并尝试运行,往往难以轻松处理深藏其中的问题。幸运的时候,代码崩溃还能显示明确的错误信息;但如果运气不好,应用程序仍能勉强运行,只是结果与开发者预期相去甚远。


什么是调试?


所谓调试,就是修复软件缺陷的艺术。修复 bug 并不高深,大多数问题其实就是由字符错录或代码行里的小问题引发,但查找 bug 却是无缘艰难。开发人员往往得花上大量时间才能抽丝剥茧、厘清问题的根源。


以下几种方法能帮助大家有效规避错误:


  1. 使用高质量的代码编辑器,应具备行编号、彩色编码、代码校验、自动补全、括号匹配、参数提示等功能。

  2. 使用 Git 等源代码控制系统以管理代理修订工作。这些工具能帮助开发者检查更新,定位 bug 出现的方式、时间和位置。

  3. 采用 bug 跟踪系统,例如 Jira、FogBugz 以及 Bugzilla 等。它们能向开发者报告 bug、高亮显示重复项、记录重现步骤、确定 bug 严重性、计算优先级、分配开发人员、记录讨论线索并跟踪修复进度。

  4. 使用测试驱动开发(TDD)方法。TDD 是一种开发过程,鼓励开发者在编写函数之前先用编码测试该函数的运行效果。

  5. 尝试使用代码解释或结对编程等方法同其他开发者携手合作,对方提供的全新视角能帮助我们发现自己遗漏的问题。


但没有哪种解决方案能够直接消除所有错误,而且任何一种编程语言都免不了出现以下几种错误类型。


语法错误


如果代码内容未遵循某些语言规则,就会触发错误。常见的语法错误包括拼写错误或缺少括号等。


VS Code 等优秀代码编辑器能帮助大家在实际运行代码之前,预先检查各种常见的 Node.js 问题:


  • 将有效和无效语句标记为彩色形式;

  • 自动补全函数和变量名称;

  • 高亮显示匹配的括号;

  • 自动缩进代码块;

  • 为函数、属性和方法提供参数提示;

  • 检测无法访问的代码;

  • 重构混乱函数。


可以使用 ESLint 等代码检查器寻找各种语法问题,或者不符合正常编码风格的情况。使用以下命令,即可将 ESLint 安装为全局 Node.js 模块:


npm i eslint -g
复制代码


而后通过命令行检查 JavaScript 文件:


eslint code.js
复制代码


ESLint for VS Code 扩展程序的效果更好,能在我们输入的同时对代码内容做验证:



逻辑错误


逻辑错误意味着我们的代码可以运行,但却无法达成预期的效果。例如,用户无法使用有效凭证正常登录;报告中的统计信息不正确;用户数据未被保存至数据库等。引发逻辑错误的原因多种多样,包括:


  • 使用了不正确的变量名称;

  • 使用了不正确的条件,例如应该是 if(x>5) 而非 if(x<5);

  • 使用了无效的函数、参数或算法。


我们往往需要分步执行代码,并在过程当中检查特定的运行状态点。


运行时错误


运行时错误主要影响的是应用程序的执行过程。代码执行可能并不出错,但也随时可能被无效的用户输入而意外触发。例如:


  • 尝试将某个值除以零;

  • 访问目前已不存在的数组项或数据库记录;

  • 在不具备适当访问权限的情况下,尝试写入文件;

  • 不正确的异步函数实现会引发“内存溢出”崩溃。


众所周知,运行时错误往往很难重现,所以保持良好的日志记录习惯至关重要。


Node.js 调试中的环境变量


主机操作系统中的环境变量负责控制 Node.js 应用程序的具体设置。最常见的环境变量是 NODE_ENV,一般在调试时被设定为 development、在 production 过程中则被设定为 production。


大家可以在 Linux/macOS 上这样设置环境变量:


NODE_ENV=development
复制代码


在 Windows(旧版 DOS)命令行中这样设置:


set NODE_ENV=development
复制代码


在 Windows Powershell 上则是这样设置:


$env:NODE_ENV="development"
复制代码


应用程序可以检测环境设置,并在必要时启用调试消息,例如:


// running in development mode?const DEVMODE = (process.env.NODE_ENV === 'development');if (DEVMODE) {  console.log('application started in development mode');}
复制代码


NODE_DEBUG 需要使用 Node.js util.debuglog 来启用调试消息(后文中的 Node.js util.debuglog 部分将具体介绍)。另外,请注意检查主模块和框架的说明文档,了解更多日志记录选项。


使用 Node.js 命令行选项进行调试


在启动应用程序时,您可以将命令行选项传递给 node 或 nodemon 运行时。其中最有用的选项之一当数—trace-warnings,它会在无法解析或拒绝 promise 时输出栈跟踪信息:


node --trace-warnings index.js
复制代码


其他选项包括:


  • –enable-source-maps: 使用 TypeScript 等转译器时,启用源映射

  • –throw-deprecation: 在使用已被弃用的功能时,抛出错误

  • –inspect: 激活 V8 检查器(具体请参阅后文中的 Node.js V8 检查器部分)


使用控制台日志进行调试


最简单的应用程序调试方法,就是在执行期间将值输出至控制台:


console.log(`myVariable: ${ myVariable }`);
复制代码


有些开发者坚持认为 console.log() 这东西没有意义,因为代码本身一直在不断变更,而且还有更好的调试选项可用。话虽没错,但大家还是会经常用到 console.log(),而且任何能提高编程效率的工具都有价值。控制台日志就是这样一种快速且实用的选项,能帮助大家切实找到并修复 bug。


当然,除了标准的 console.log() 之外,大家也可以考虑其他几个选项:



console.log() 支持以逗号分隔各值的列表,例如:


let x = 123;console.log('x:', x);// x: 123
复制代码


ES6 的解构赋值能以更简洁的方式提供类似输出:


console.log({ x });// { x: 123 }
复制代码


util.inspect 能够格式化对象以方便阅读,而 console.dir() 能会帮助大家完成其他费时费力的工作:


console.dir(myObject, { depth: null, color: true });
复制代码


Node.js util.debuglog


Node.js 的标准 util 模块提供 debuglog 方法,能够按特定条件将日志消息写入 STDERR:


const util = require('util');const debuglog = util.debuglog('myapp');
debuglog('myapp debug message [%d]', 123);
复制代码


当大家将 NODE_DEBUG 环境变量设置为 myapp 或通配符形式(例如或*my*)时,控制台会显示以下调试消息:


MYAPP 4321: myapp debug message [123]
复制代码


其中 4321 代表 Node.js 的进程 ID。


使用日志模块进行调试


Node.js 支持各种第三方日志记录模块,我们可以根据需求具体选择消息传递级别、详细程度、排序、文件输出、分析、报告等:


  • cabin

  • loglevel

  • morgan (Express.js 中间件)

  • pino

  • signale

  • storyboard

  • tracer

  • winston


使用 Node.js V8 检查器进行调试


Node.js 是围绕 V9 JS 引擎构建的打包器。V8 引擎中包含自己的检查器和调试客户端,这里就从检查参数起步(注意,不要将其与后文中「使用 Chrome 调试 Node.js 应用程序」中提到的—inspect 标志混淆):


node inspect index.js
复制代码


调试器会在第一行暂停,并显示以下 debug 提示:


$ node inspect index.js< Debugger listening on ws://127.0.0.1:9229/b9b6639c-bbca-4f1d-99f9-d81928c8167c< For help, see: https://nodejs.org/en/docs/inspector<connecting to 127.0.0.1:9229 ... ok< Debugger attached.<Break on start in index.js:4  2  3 const> 4   port = (process.argv[2] || process.env.PORT || 3000),  5   http = require('http');  6
复制代码


输入 help 可查看命令列表。大家可以使用以下步骤逐步跑通应用程序:


  • cont 或 c: 继续执行

  • next 或 n: 运行下一条命令

  • step 或 s: 单步执行被调用函数

  • out 或 o: 跳出被调用函数并返回其调用者

  • pause: 暂停运行代码


还可以:


  • 使用 watch(‘x’) 查看变量值;

  • 使用 setBreakpoint()/sb() 命令设置断点(也可以在代码中插入 debugger; 语句);

  • restart 重启脚本;

  • .exit 退出调试器(请注意开头的. 句点)。


整个操作过程似乎不太方便,确实如此。所以除非实在没有其他方法,否则尽量不要使用内置的调试客户端。


使用 Chrome 调试 Node.js 应用


使用—inspect 标志启动 Node.js V8 检查器:


node --inspect index.js
复制代码


(nodemon 也支持此标志。)


此命令会在 127.0.0.1:9229 端口上启动侦听调试器:


Debugger listening on ws://127.0.0.1:9229/4b0c9bad-9a25-499e-94ff-87c90afda461
复制代码


如果大家在其他设备或 Docker 容器上运行 Node.js 应用,请确保端口 9229 可以访问,具体使用以下命令授予远程访问权限:


node --inspect=0.0.0.0:9229 index.js
复制代码


与—inspect 不同,我们可以使用—inspect-brk 停止对首条语句的处理,以便逐步分步执行。


打开 Chrome 网络浏览器(或者其他基于 Chromium 内核的浏览器),并在地址栏中输入 chrome://inspect:



几秒后,您的 Node.js 应用就会显示为 Remote Target。如果仍未找到,请选中 Discover network targets,而后单击 Configure 按钮为运行应用的设备添加 IP 地址和端口。


单击目标的 inspect 链接以启动 DevTools。对于熟悉在浏览器上调试客户端应用的朋友,整个操作流程应该非常顺畅。



要直接从 DevTools 加载、编辑和保存文件,请打开 Sources 窗格,单击 + Add folder to workspace 向工作区添加文件夹。之后选择 Node.js 文件的位置,而后单击 Agree。现在,我们可以从左侧窗格或按 Ctrl | Cmd + P 并输入文件名。


单击任何行号以设置断点(显示为蓝色标记):



这里的 breakpoint 断点,负责指定调试器应在何处暂停处理。我们可以借此检查程序状态,包括局部和全局变量。您可以定义任意数量的断点,或向代码中添加调试器语句,这些语句会在调试器开始运行时停止处理。



右侧面板显示以下内容:


  • Watch 窗格中,您可以通过单击 + 图标以输入变量名称并监视变量

  • Breakpoint 窗格中,您可以查看、启用和禁用断点

  • Scope 窗格中,您可以检查所有变量

  • Call Stack 窗格中,您可以查看达到此点前所调用的所有函数


Paused on breakpoint“在断点处暂停”上方,会出现一行图标。



从左至右,各图标分别对应以下操作:


  1. resume execution: 继续处理至下一断点

  2. step over: 执行下一条命令,但停留在当前函数内;不跳转至命令所调用的任何其他函数

  3. step into: 执行下一条命令,并跳转至命令所调用的任何其他函数

  4. step out: 继续处理至函数末尾,而后返回至调用命令

  5. step: 与 step into 类似,但不会跳转至 async 函数中

  6. deactivate all breakpoints:禁用所有断点

  7. pause on exceptions: 当发生错误时,停止处理


在 Chrome 中设置条件断点


假设我们有一个运行 1000 次迭代的循环,但真正需要关注的是最后一次迭代的状态:


for (let i = 0; i < 1000; i++) {  // set breakpoint here?}
复制代码


这里我们当然无需对着 resume 单击 999 次,而是右键单击该行并选择 Add conditional breakpoint 添加条件断点,而后输入条件,例如 i=999:



条件断点会显示为黄色,而非蓝色。


在 Chrome 中设置日志点


日志点为 console.log(),不涉及任何代码!执行此代码时会输出一条表达式,但与断点不同的是,处理过程不会暂停。要添加日志点,先右键单击任意行,选择 Add log point 添加日志点,而后输入表达式,例如’loop counter I’,i。



使用 VS Code 调试 Node.js 应用


VS Code 支持 Node.js,而且提供内置调试客户端。在本地系统上运行 Node.js 应用时无需任何配置。只要打开启动脚本(一般为 index.js),激活 Run and Debug 窗格,点击 Run and Debug Node.js 按钮,再选择相应的 Node.js 环境。之后单击任意行即可激活断点。


如果您正在运行 Web 应用程序,可在任意浏览器中打开,VS Code 会在遇到断点或 debugger 语句时停止执行:



VS Code 调试方法与 Chrome DevTools 中的 Variables、Watch、Call stack 和 Breakpoints 窗格类似。其中 Loaded Scripts 窗格会显示应用程序所加载的各脚本,也包括 Node.js 的内部脚本。


操作图标工具栏提供以下功能:


  1. resume execution: 继续处理至下一断点

  2. step over: 执行下一条命令,但停留在当前函数之内;不跳转至命令调用的任何函数

  3. step into: 执行下一条命令,并跳转至它调用的任何其他函数

  4. step out: 继续处理至函数末尾,而后返回至调用命令

  5. restart:重新启动应用程序和调试器

  6. stop:停止应用程序和调试器


与 Chrome DevTools 类似,我们可以右键单击任意行来添加:


  • 标准断点

  • 在指定条件下停止程序的条件断点,例如 x>3

  • 计算花括号中表达式的日志点,例如 URL:{ reg.url }


关于更多信息,请参阅在 VS Code 中调试(https://code.visualstudio.com/docs/introvideos/debugging)。


VS Code 高级调试配置


如果希望在另一台设备或虚拟机上调试代码,或者需要使用其他替代启动选项(例如 nodemon),我们可能须进一步调整 VS Code 配置。


编辑器将启动配置存储在项目中隐藏的.vscode 文件夹内的 launch.json 文件。要生成此文件,请点击 Run and Debug 窗格上方的 create a launch.json file 创建文件,而后选择 Node.js 环境。



可以使用 Add Configuration 按钮,将任意数量的配置设置对象添加至”configurations”: [] 数组当中。VS Code 能够:


  1. Launch 启动 Node.js 进程本身,或者

  2. Attach 附加至调试 Web Socket 服务器,该服务器可能运行在远程计算机或 Docker 容器中。


以上截屏所示,为 nodemon 的启动配置。其中 Add Configuration 按钮提供 nodemon 选项,我们可以编辑其中的 program 属性以指向入口脚本 (${workspaceFolder}/index.js)。


保存 launch.json,而后在 Run and Debug 窗格上方的下拉菜单中选择 nodemon,接着单击绿色的运行图标:



nodemon 会启动我们的应用程序,之后即可正常编辑代码并设置断点或日志点。


关于更多信息,请参阅 VS Code 启动配置(https://code.visualstudio.com/docs/editor/debugging#_launch-configurations)。


VS Code 可以调试任何 Node.js 应用程序,而善用以下扩展能让调试过程更轻松:


  • Remote - Containers: 接入运行在 Docker 容器中的应用

  • Remote - SSH: 接入远程服务器上运行的应用

  • Remote - WSL: 接入运行在 Windows 上 Linux in WSL 中的应用


Node.js 的其他调试选项


参考 Node.js 调试指南:https://nodejs.org/en/docs/guides/debugging-getting-started/


主要为 Visual Studio、JetBrains、WebStorm、Gitpod 和 Eclipse 等 IDE 和编辑器提供调试建议。


ndb 提供更好的调试体验,同时具备强大功能,例如附加至子进程和能够限制文件访问的脚本黑盒。


IBM report-toolkit for Node.jshttps://github.com/ibm/report-toolkit


在 node 运行时使用 --experimental-report 选项,即可分析数据输出。


最后,LogRocket 和 Sentry.io 等商业服务可以与客户端和服务器上的实时 Web 应用程序相集成,帮助用户记录真实发生的错误。


总结


过去十年以来,JavaScript 和 Node.js 的调试已经变得愈发轻松。我们可以用各种实用工具定位问题,使用 console.log() 快速查找 bug。如果面对更复杂的问题,Chrome DevTools 或者 VS Code 可能是更合适的选项。熟悉掌握这些工具将帮助大家编写出更健壮的代码,同时显著缩短在 bug 修复上投入的时间和精力。


原文链接:


https://blog.openreplay.com/an-introduction-to-debugging-in-nodejs/


相关阅读:


Node.js 未来发展趋势

Node 之父着急宣布:Deno 将迎来重大变革,更好地兼容

Node 版本控制

Node.js 20 正式发布


2023-07-27 17:493573

评论

发布
暂无评论
发现更多内容

中国数字人民币官方宣传片来袭!DCEP:开启“无现金新时代”!

CECBC

5分钟速读之Rust权威指南(十一)

wzx

rust

高可用DevHa实践,告诉你生产环境0性能故障是如何做到的!

TakinTalks稳定性社区

压测 性能调优 全链路压测 系统稳定高可用 性能压测

智慧党建平台搭建,党建干部管理系统,智慧组工平台解决方案

week5作业

Geek_2e7dd7

架构实战营

低代码实现传统装饰企业的管理跃迁

华为云开发者联盟

低代码 华为云 计算 低代码开发 AppCube

appium 入门参考

37手游iOS技术运营团队

ios 测试 自动化测试 iOS Developer

探秘区块链技术在计算机取证过程中的机制与应用

CECBC

计算社会科学 - DAY 17

Qien Z.

5月日更

鸿蒙轻内核M核源码分析:数据结构之任务排序链表

华为云开发者联盟

鸿蒙 数据结构 任务排序链表 双向链表数组 鸿蒙轻内核

Django 之 Models(Models 模型 & 数据表关系)

若尘

django model Python编程 5月日更

并发王者课-青铜7:顺藤摸瓜-如何从synchronized中的锁认识Monitor

MetaThoughts

Java 多线程 并发

密码学系列之:SAFER

程序那些事

密码学 程序那些事 SAFER

英特尔院士斯旺:由外而内重塑芯片设计

E科讯

用图数据库可视化探索 Chia Network 区块链数据

古思为

区块链 可视化 图数据库

5 月 28 日 - 29 日阿里云峰会视频云专场直播预告

阿里云视频云

阿里云 音视频

五一假期旅游完突然收到(余额宝)面试,四面成功拿下offer

Java架构师迁哥

一场“测谎”人机对战背后的故事:度小满的技术进击之路

脑极体

代码精进之路学习笔记

escray

学习 极客时间 5月日更

为什么不推荐C++?

实力程序员

从源码角度研究Java动态代理

叫我阿柒啊

动态代理 代理模式 rmi

MySQL事务处理特性的实现原理

华为云开发者联盟

MySQL 数据库 innodb 事务 隔离

Dubbo 服务治理简介

青年IT男

dubbo

面向WEB开发人员的Docker(六):使用nginx部署静态网站

devpoint

Docker

眼观六路耳听八方还不知疲倦?数仓智能运维服务体系是怎么做到的?

华为云开发者联盟

数据库 数据仓库 监控 智能运维 数据库监控

webRTC的标准与发展

anyRTC开发者

音视频 WebRTC RTC

人生算法:做好自己这家公司的CEO

石云升

读书笔记 思维模型 5月日更

V8数据存储(上篇):栈和堆

梁龙先森

大前端 浏览器

【Flutter 专题】118 图解特殊利器 ShaderMask 着色器

阿策小和尚

5月日更 Flutter 小菜 0 基础学习 Flutter Android 小菜鸟

【玩转PDF】贼稳,产品要做一个三方合同签署,我方了!

牧小农

JVM

2021 全球技术领导力峰会 融云布道技术领导力进阶之路

融云 RongCloud

关于Node.js调试,你需要了解的一切_架构/框架_Craig Buckler_InfoQ精选文章