|
为什么要使用debugger这篇文章将介绍如何使用断点来进行JavaScript调试。在读这篇文章之前,需要问一个问题:为什么要使用断点来进行调试?我们首先需要认可使用断点的是必要的,否则下文介绍的所有断点调试方法都会是废话。console.log是前端开发最常用的调试手段,它简单直接解决一部分问题。但当遇到十分复杂的问题,console.log就会变得不趁手。比如:一个逻辑复杂的算法如果你刷过leetcode一定深有体会,算法某个测试用例报错了,有时很难光靠目测找出有问题的那个方法。一个复现步骤十分繁琐的bug。花了10分钟好不容易复现了,但是只跟踪到某行代码,需要第二次添加log才能继续寻找问题。查看log->添加log->查看log...这个过程重复几遍,今天剩下的砖就搬不完了。一段运行流程冗长的代码一段没有注释、起名随意的代码server端代码有nodejs服务端开发经验的同学相信有过在postman和ide之间反复横跳的经历,如果光靠log,对于一个巨大的复杂对象,控制台是不好查看全貌的。如果一个接口还涉及到数据库增删、第三方依赖,那么复原上一次请求造成的后果也是一件痛苦的事情。在这些情况下,断点调试是非常有价值的,将debug的时间复杂度从O(n)降到O(1),让搬砖更快乐。这是文章的内容大纲:Chromedebugger基本用法VSCode调试SPA应用Chrome调试NodejsVSCode调试NodejsChromedebugger基本用法最简单的断点调试,就是在代码中加一句debugger,然后到浏览器中刷新页面,这时候浏览器就会在debugger语句那停止执行。为了方便理解,引入一个简单例子,在一个文件夹中创建index.html和index.js,然后在index.html中引入index.js。index.js内容如下:// 国际惯例,helloworld。const greet = () => { const greeting = "hello debugger"; // 浏览器执行到这里将会暂停 debugger console.log(greeting);};greet();console.log("js evaluation done");执行命令:npm i -g serveserve .然后访问http://localhost:5000并打开开发者工具。这时候我们的helloworld断点就打上了,就像这样:d8090eb4-4a1f-4dfb-bf30-c08c762d66ad图中分为四个区域,蓝色区域用于文件选择,Page一栏是指当前页面中的JS文件,Filesystem会显示我们系统中的文件。通常我们使用Page。粉色是代码的行号和内容。代码的行号处可以通过点击来添加新的断点,再次点击后取消。黄色区域用于控制代码的执行,只需要掌握前四个按钮的含义,就可以应付绝大多数场景。按钮1是让代码继续执行(resume),如果遇到下一个断点就会再次中断执行。按钮2可以让浏览器执行当前行(图中是第3行),然后在下一行中断代码,按钮3是进入当前函数,查看函数具体内容。假设我们当前停在第7行greet(),点击按钮3就会进入greet方法中(也就是第2行)。如果不想再看greet方法了,就点击按钮4,跳出这个方法,回到第8行。绿色区域可以查看变量的内容和当前的调用栈。debugger是最简单粗暴的打断点方式,但是需要修改我们的代码。需要注意的是,上线前必须删除这些语句。也可以通过配置webpack来自动去除。不过终究还是有些不方便,所以我们来看下如何通过vscode来简化打断点的方式。VSCode调试SPA应用首先我们使用Vite来创建一个Vue应用用于演示(React步骤类似)。# 创建 vut-ts 应用npm init vitecd hello-vitenpm install# 调用 VS Code cli 打开项目,# 或者手动在VSCode打开。code .npm run dev然后在VSCode中新建一个文件.vscode/launch.json,填入这些内容:{ "version": "0.2.0", "configurations": [ { "type": "pwa-chrome", "request": "launch", "name": "Launch Vue project", // 这里填入项目的访问地址 "url": "http://localhost:3000", "webRoot": "${workspaceFolder}" }, ]}然后使用cmd+q退出你正在运行的Chrome(这步很重要,不能跳过),按f5启动VSCode的调试功能。VSCode就会帮你启动一个Chrome窗口,并访问上述配置的中的url。这时候我们的断点就生效了,可以一步一步地控制代码的运行,找出bug来源。7f962a01-e7eb-4ca8-9888-68177fbb07dd这里有一个实用的小技巧,就是在BREAKPOINTS中,把UncaughtExceptions勾上,这样在代码报错的地方,就会自动中断执行。当我们遇到一个报错时,采用这个方法可以省去定位问题代码的时间。402686f5-4076-43e9-b345-6814fd89ae45另外我们可以发现,在VSCode断点生效时,ChromeDevtools也会同步这个展示这个断点。59038bd1-67aa-4b42-8320-54f718bab48e在VSCode中,调试有两种模式,分别是launch和attach。由于真正执行代码的是Chrome中的JS引擎,所以是否中断代码的控制权是在Chrome手里的。那为什么VSCode的断点可以控制代码的中断呢?是因为VSCode通过devtools-protocol向Chrome发起指令,告诉Chrome需要在哪一行代码暂停执行。这个发送指令的过程,被称作attach。而launch的过程包含attach,即先launch(启动)浏览器,然后attach(附加)断点信息。所以attach模式是launch模式的子集。听起来好像launch模式会更方便,为我们省去了手动启动浏览器的过程。但是这存在一个问题,如果同时开发多个前端工程会怎样?每个工程启动一个调试进程,就会打开多个浏览器,那么在多个浏览器之间切换就会显得很麻烦。我们可以使用attach模式解决这个问题。首先我们使用命令行启动Chrome。使用命令行的原因是,我们需要给Chrome的启动传参。# 运行这条命令前需要cmd+q退出已运行的Chrome/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222# 如果看到这个输出,说明传参成功。DevTools listening on ws://127.0.0.1:9222/devtools/browser/856a3533-ca5c-474f-a0cf-88b7ae94c75bVSCode和Chrome是通过websocket交流,--remote-debugging-port指定了websocket使用的端口。然后我们将launch.json文件修改成这样:{ "version": "0.2.0", "configurations": [ { "type": "pwa-chrome", "request": "attach", "name": "Vue Application", // 项目访问的 url "url": "http://localhost:3000", //websocket端口,需要与 --remote-debugging-port参数保持一致。 "port": 9222, "webRoot": "${workspaceFolder}" }, ]}注意在启动VSCode调试之前,需要在Chrome中打开http://localhost:3000这个页面。然后我们在VSCode中打上断点,刷新浏览器,代码就成功停在断点处了。第二个、第n个工程都可以采用相同的配置,区别是url字段要根据项目配置进行修改。Chrome调试Nodejs上文讲的是如何调试页面,接下来我们聊如何调试nodejs应用。首先来一个最容易上手的例子,创建一个helloworld:// debug.js 文件const greeting = 'hello nodejs debugger'debuggerconsole.log(greeting)然后运行这个文件node --inspect-brk debug.jsDebugger listening on ws://127.0.0.1:9229/b9a6d6bf-baaa-4ad5-8cc6-01eb69e99f0aFor help, see: https://nodejs.org/en/docs/inspector--inspect-brk表示运行这个js文件的同时,在文件的第一行打上断点。然后打开Chrome,进入Devtools。点击红框处的按钮,就会打开一个nodejs专用的调试窗口,并且代码在第一行中断了。074ccabf-1833-4393-8566-52b0a4cf3568nodejs调试窗口:cc3d93a5-d97c-4799-98a2-936dfe18c887这个方式的实质是,ChromeDevtool根据v8引擎的调试协议向nodejs进程发送指令,控制代码的运行。可以发现,在网页的调试中,Chrome是接受指令的一方,而在nodejs调试中,Chrome转身变为发送指令的一方。所谓从悲惨的乙方华丽转身成甲方。node默认的websocket端口是9229,如果有需要的话(比如端口被占用了),我们可以通过一些方式改变这个端口。node --inspect=9228 debug.jsDebugger listening on ws://127.0.0.1:9228/30f21d45-9806-47b8-8a0b-5fb97cf8bb87For help, see: https://nodejs.org/en/docs/inspector在我们打开Devtool时,Chrome默认检查9229端口,但当我们改变了端口号后,就需要手动去指定Chrome检查的地址了。点击下图中的Configure按钮,输入127.0.0.1:9228,然后点击Done。这时候RemoteTarget中就会出现刚才启动的node进程,点击inspect就可以进入调试了。494fcb5f-b688-4a26-b868-b4c284327afc使用VSCode调试Nodejs到此为止,我们已经达成调试node的目的,但还有些繁琐,不够自动化。我们可以使用VSCode,来一键启动调试。用VSCode打开刚才的工程,然后在launch.json中输入这些:{ "version": "0.2.0", "configurations": [ { "type": "pwa-node", "request": "launch", "name": "Launch rogram", "skipFiles": [ "/**" ], // ${file} 的意思是,当我们启动调试的时候,调试的程序就是当前focus的文件。 "program": "${file}" } ]}这时候切换到index.js文件,按f5启动调试程序,当运行到第二行debugger语句的时候,就会自动暂停执行。也可以点击代码行数的左侧来打断点。另外,这个配置是支持TypeScript的,我们只需要index.js重命名为index.ts,然后正常启动调试就行。ConditionalBreakpoint条件断点在某些情况下,我们不希望打上的每个断点都发挥作用,而是在执行到断点那行,且满足某个条件再中断代码执行。这就是条件断点。for(leti=0;i
|
|