#0 node 正确的书写方式
为了防止后面出现混乱的各种书写, 先来了解一下如何正确书写 node 的名称.
下面使用来自 @bitandbang 推文中的图片展示如何正确书写 node 名称.
node 名称的正确书写方式
--inspect 参数
本地开发, 无论是 web 应用还是命令行工具, 使用 --inspect-brk 参数启动程序, 然后结合 Chrome DevTools 调试恐怕能满足大多数场景了.
具体步骤:
通过 --inspect-brk 参数启动程序, 会进入调试模式.
$ `node --inspect-brk index.js`
这里使用 --inspect-brk 而非 --inspect 可保证代码第一时间断在开程序开头. 如果使用后者, 有可能无法进行后续操作.
打开 Chrome 新开标签页访问 Chrome://inspect. 不出意外会看到刚刚创建的一个调试实例, 直接点击 inspect 即可启动调试. 因为是 --inspect-brk 启动的, 调试界面打开后会断在程序开头. 后面在哪里加断点就有很大自主权了.
Chrome://inspect 界面
需要注意的是, 因为此时断在了程序开始, 程序中其他文件可能没加载. 所以无法看到. 这种情况下, 可事先在需要加断点的地方写上 debugger.
子进程中代码的调试
另一个需要注意的地方就是子进程. 对于 子进程 中的代码, 是无法断点的, 这是调试大多数框架及复杂程序时的痛点.
一个简单的子进程示例:
index.JS
- var cp = require('child_process');
- var child = cp.fork('./child');
- child.on('message', function(m) {
- console.log('received:' + m);
- });
- child.send('Please up-case this string');
child.JS
- process.on('message', function(m) {
- debugger;
- // Do work (in this case just up-case the string
- m = m.toUpperCase();
- // Pass results back to parent process
- process.send(m.toUpperCase(m));
- });
这里, node --inspect-brk index.JS 启动调试后, child.JS 中的 debugger 并不会生效, 因为它的代码在子进程中.
这也就是为什么, 当你想调试 webpack 编译, 恰好又用了类似 happypack 这种多进程加速编译的工具时, 发现 loader 及 插件中无法断点的原因.
又比如, 调试 eggjs, 它也是多进程的模型, 业务代码是运行在 worker 进程中的, 直接通过 node 的调试参数肯定是不行的. 当然框架一般会有自身配套的调试方案, 你可以安装 egg 的 vscode 调试插件, 或者使用 egg-scripts 来启动调试.
那是不是就无能为力了? 当然不是, 只是需要费劲一点. 我们需要找到开启子进程的地方, 在开启的时候加上调试参数.
还是上面的示例, 改造主文件为如下:
- var cp = require('child_process');
- +var child = cp.fork('./child',[],{execArgv:['--inspect-brk']});
- child.on('message', function(m) {
- console.log('received:' + m);
- });
- child.send('Please up-case this string');
这样, 就表示以调试模式来运行子进程中的代码, 此时启动程序不要加 inspect, 因为那是开启对主进程的调试, 直接运行程序即可. node index.JS. 然后我们会在 Chrome://inspect 看到子进程已经 attach 到了调试界面.
所以, 无论是通过 require('child_process' 的 exec 还是 spawn, 只需要找到开启子进程的地方, 加上调试参数.
但问题是, 就看你能不能正确地找到所使用的框架工具他们开启子进程的地方.
善用 npx
调试 node 模块时, 特别是 NPM 包, 你需要手动拼出该模块的入口文件的路径, 类似 node -inspect node_modules/webpack/bin/webpack.JS, 但通过 npx 则不用, 因为 npx 会自动在项目的 node_modules 或系统全局中寻找模块的入口文件, 甚至如果本机没有安装, 它还会自动搜索 registry 自动安装后执行.
以至于你在初始化一个项目时, 可使用如下命令:
- $ npx license mit> LICENSE
- $ npx gitignore node
- $ npx covgen YOUR_EMAIL_ADDRESS
- $ NPM init -y
即使你本地并没有安装 mit,gitignore,covgen 等 NPM 包.
使用 npx 时可通过 -node-arg 来传递参数给 node. 因为本质上 npx 也是执行 JS 文件, 与直接使用 node 命令来启动文件没什么差异.-node-arg 指定的参数会透传给 node, 所以, 可以这样来启动一个 NPM 包的调试:
$ npx -node-arg=-inspect-brk webpack
node 内建的 debugger
node 自带的 v8 调试工具, 是个命令行工具. 操作起来是难用, 但在远端服务器上这种不能使用 Chrome Devtools 进行可视化调试的场景下, 就显得很有用了, 比如调试路由重定向次数过多这种瞬间发生的问题, 它能将代码及时在服务器上断下来, 让我们慢慢分析现场.
$ node inspect index.JS
node 自带的 debugger
进入调试模式后, 代码会断在开始处. 可通过以下常用命令进行 debug:
c/cont: 断续执行, 类似于 Chrome DevTools 中的 F8
n/next: 步进, 类似于 Chrome DevTools 中的 F10
step/s: 进入, 类似于 Chrome DevTools 中的 F11
setBreakpoint()/sb(): 设置断点.
通过调用该函数可对代码设置断点.
直接调用则在当前所处的行设置断点.
sb(line_number) 传递一个行数, 对相应行设置上断点.
sb(file_name,line_number) 传递文件名及行数, 可对非当前文件进行断点的设置.
clearBreakpoint: 参数与 setBreakpoint 类似, 作用是清除断点.
breakpoints, 查看设置的断点.
观察变量的值. 在这种调试模式下, 可通过输入 repl 进入 REPL(Read-Eval-Print-Loop) 模式来查看变量的值.
通过进入 REPL 模式查看断点处的变量值
实际使用中发现个弊端, 就是打印出来的对象是不完整的, 如上图. 如果想查看没展示出来的属性, 那就得记住属性名, 然后手动点出来. 你当然可以通过 JSON.stringify(variable) 将变量转字符后打出来. 但 JSON 序列化可并不是处处都管用, 比如 koa 中的 response, request 对象, 如果尝试进行 JSON 序列化, 会报 JSON 循环引用的错误. 而且在这里的 REPL 环境下, 不能调用 node 模块, 不然就可以通过自带的 require('util').inspect(variable) 来打印了.
如果每次断在某处时, 都需要查看某个变量的值, 可通过设置 watcher 来更加方便地查看.
> watch('my_expression')
日志加 tail -f
服务器上面更加常用的应该还是日志加 tail, 配合 -f 参数, 可时实将最新的 log 输出到命令行.
- $ tail -f /your/logs/log
- Remote Debug
Remote Debug 这个就有点厉害了, 没配置过, 获取相应服务器权限设置好之后, 估计没有比这个更便捷的调试服务器上代码的方式了. 在有些资源或服务只在服务器环境才有的情况下, 本地又不好还原场景.
来源: https://www.cnblogs.com/Wayou/p/node_debug.html