JavaScript 断点调试技巧

大家好,我是若川。最近组织了源码共度活动:1个月,200+人,一起读了4周源码,参与的小伙伴都表示收获很大。如果感兴趣可以点击链接扫码加我微信 ruochuan12。之前推荐过很多次调试文章,说明调试的重要性,重要的是自己动手实践。前端容易忽略的 debugger 调试技巧、写 Node.js 代码,从学会调试开始


为什么要使用 debugger

这篇文章将介绍如何使用断点来进行 JavaScript 调试。在读这篇文章之前,需要问一个问题:为什么要使用断点来进行调试?

我们首先需要认可使用断点的是必要的,否则下文介绍的所有断点调试方法都会是废话。console.log 是前端开发最常用的调试手段,它简单直接解决一部分问题。但当遇到十分复杂的问题,console.log 就会变得不趁手。比如:

  • 一个逻辑复杂的算法

    如果你刷过 leetcode 一定深有体会,算法某个测试用例报错了,有时很难光靠目测找出有问题的那个方法。

  • 一个复现步骤十分繁琐的bug。

    花了10分钟好不容易复现了,但是只跟踪到某行代码,需要第二次添加 log 才能继续寻找问题。查看log -> 添加log -> 查看log... 这个过程重复几遍,今天剩下的砖就搬不完了。

  • 一段运行流程冗长的代码

  • 一段没有注释、起名随意的代码

  • server 端代码

    有 nodejs 服务端开发经验的同学相信有过在 postman 和 ide 之间反复横跳的经历,如果光靠 log,对于一个巨大的复杂对象,控制台是不好查看全貌的。如果一个接口还涉及到数据库增删、第三方依赖,那么复原上一次请求造成的后果也是一件痛苦的事情。

在这些情况下,断点调试是非常有价值的,将 debug 的时间复杂度从 O(n) 降到 O(1),让搬砖更快乐。

这是文章的内容大纲:

  • Chrome debugger 基本用法

  • VS Code 调试 SPA 应用

  • Chrome 调试 Nodejs

  • VS Code 调试 Nodejs

Chrome debugger 基本用法

最简单的断点调试,就是在代码中加一句 debugger,然后到浏览器中刷新页面,这时候浏览器就会在 debugger 语句那停止执行。

为了方便理解,引入一个简单例子,在一个文件夹中创建 index.htmlindex.js,然后在 index.html 中引入 index.jsindex.js 内容如下:

// 国际惯例,hello world。
const greet = () => {const greeting = "hello debugger";// 浏览器执行到这里将会暂停debuggerconsole.log(greeting);
};greet();console.log("js evaluation done");

执行命令:

npm i -g serve
serve .

然后访问 http://localhost:5000并打开开发者工具。

这时候我们的 hello world 断点就打上了,就像这样:

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 来简化打断点的方式。

VS Code 调试 SPA 应用

首先我们使用 Vite 来创建一个 Vue 应用用于演示(React步骤类似)。

# 创建 vut-ts 应用
npm init vite
cd hello-vite
npm install
# 调用 VS Code cli 打开项目,
# 或者手动在 VS Code 打开。
code .
npm run dev

然后在 VS Code 中新建一个文件 .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 启动 VS Code 的调试功能。VS Code 就会帮你启动一个 Chrome 窗口,并访问上述配置的中的 url。这时候我们的断点就生效了,可以一步一步地控制代码的运行,找出 bug 来源。

7f962a01-e7eb-4ca8-9888-68177fbb07dd

这里有一个实用的小技巧,就是在 BREAKPOINTS 中,把 Uncaught Exceptions 勾上,这样在代码报错的地方,就会自动中断执行。当我们遇到一个报错时,采用这个方法可以省去定位问题代码的时间。

402686f5-4076-43e9-b345-6814fd89ae45

另外我们可以发现,在 VS Code 断点生效时,Chrome Devtools 也会同步这个展示这个断点。

59038bd1-67aa-4b42-8320-54f718bab48e

在 VS Code 中,调试有两种模式,分别是 launchattach。由于真正执行代码的是 Chrome 中的 JS 引擎,所以是否中断代码的控制权是在 Chrome 手里的。那为什么 VS Code 的断点可以控制代码的中断呢?是因为 VS Code 通过 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-88b7ae94c75b

VS Code 和 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}"},]
}

注意在启动 VS Code 调试之前,需要在 Chrome 中打开 http://localhost:3000 这个页面。然后我们在 VS Code 中打上断点,刷新浏览器,代码就成功停在断点处了。第二个、第n个工程都可以采用相同的配置,区别是 url 字段要根据项目配置进行修改。

Chrome 调试 Nodejs

上文讲的是如何调试页面,接下来我们聊如何调试 nodejs 应用。首先来一个最容易上手的例子,创建一个 hello world:

// debug.js 文件
const greeting = 'hello nodejs debugger'
debugger
console.log(greeting)

然后运行这个文件

node --inspect-brk debug.js
Debugger listening on ws://127.0.0.1:9229/b9a6d6bf-baaa-4ad5-8cc6-01eb69e99f0a
For help, see: https://nodejs.org/en/docs/inspector

--inspect-brk 表示运行这个 js 文件的同时,在文件的第一行打上断点。然后打开 Chrome,进入 Devtools。点击红框处的按钮,就会打开一个 nodejs 专用的调试窗口,并且代码在第一行中断了。

074ccabf-1833-4393-8566-52b0a4cf3568

nodejs 调试窗口:

cc3d93a5-d97c-4799-98a2-936dfe18c887

这个方式的实质是,Chrome Devtool 根据 v8引擎的调试协议 向 nodejs 进程发送指令,控制代码的运行。可以发现,在网页的调试中,Chrome 是接受指令的一方,而在 nodejs 调试中,Chrome 转身变为发送指令的一方。所谓从悲惨的乙方华丽转身成甲方。

node 默认的 websocket 端口是 9229,如果有需要的话(比如端口被占用了),我们可以通过一些方式改变这个端口。

node --inspect=9228 debug.js
Debugger listening on ws://127.0.0.1:9228/30f21d45-9806-47b8-8a0b-5fb97cf8bb87
For help, see: https://nodejs.org/en/docs/inspector

在我们打开 Devtool 时,Chrome 默认检查 9229 端口,但当我们改变了端口号后,就需要手动去指定 Chrome 检查的地址了。点击下图中的 Configure 按钮,输入 127.0.0.1:9228,然后点击 Done。这时候 Remote Target 中就会出现 刚才启动的 node 进程,点击 inspect 就可以进入调试了。

494fcb5f-b688-4a26-b868-b4c284327afc

使用 VS Code 调试 Nodejs

到此为止,我们已经达成调试 node 的目的,但还有些繁琐,不够自动化。我们可以使用 VS Code,来一键启动调试。

用 VS Code 打开刚才的工程,然后在 launch.json 中输入这些:

{"version": "0.2.0","configurations": [{"type": "pwa-node","request": "launch","name": "Launch Program","skipFiles": ["<node_internals>/**"],// ${file} 的意思是,当我们启动调试的时候,调试的程序就是当前 focus 的文件。"program": "${file}"}]
}

这时候切换到 index.js 文件,按 f5 启动调试程序,当运行到第二行 debugger 语句的时候,就会自动暂停执行。也可以点击代码行数的左侧来打断点。

另外,这个配置是支持 TypeScript 的,我们只需要 index.js 重命名为 index.ts,然后正常启动调试就行。

Conditional Breakpoint 条件断点

在某些情况下,我们不希望打上的每个断点都发挥作用,而是在执行到断点那行,且满足某个条件再中断代码执行。这就是条件断点。

for (let i = 0; i < 10; i++) {console.log("i", i);
}

比如上面的代码,假设我们在第二行 console.log 打了断点,那么这个断点总计会中断十次。这往往是我们不希望看到的,可能我们需要的仅仅是其中某一次循环而非所有。这时候可以右键点击并选择 Add Conditional Breakpoint

eedcb461-24cc-42b4-ab8a-87bc865cb69b

这时会有一个输入框出现,我们在其中输入 i === 5

d704077c-c048-47b5-ae0f-7aa88dc54f47

这时候启动调试,就会跳过 i 为 0 - 4,直接在在 i 为 5 的时候中断代码执行。恢复代码执行后,会略过 i 为 6 - 9 的情况。

Conditional Breakpoint 在调试带有大量循环和 if else 判断时极为有用,特别是当某处的逻辑整体上是符合预期的,仅有个别特殊情况的输出错误,使用条件断点就可以略过这些正常的情况,只在个别特殊情况出现的时候,再中断执行,供我们查看各个变量是否计算正常。

总结

调试是日常工作中非常重要的能力,因为除了开发新功能外,日常有很大一部分都在调整旧的代码,处理特别条件下的逻辑错误。熟练掌握调试可以很好地提升搬砖幸福感,一个复杂的 bug 卡几小时,很容易让人心里崩溃。但也不是说断点调试是任何情况下都适用的银弹,简单的逻辑还是可以愉快地 console.log 的。

文章介绍了使用 Chrome Devtools 和 VS Code 断点调试的方法,整体上还是更推荐使用 VS Code。launch.json 只需要一次配置,后续都可以 f5 一键启动调试。另外,文中提到的各种 launch.json 文件的配置,都可以使用 VS Code 自带的工具一键生成。只要打开 launch.json,编辑器的右下角就会出现 Add Configuration 按钮,点击就可以选择自己需要添加的调试配置。

最近组建了一个江西人的前端交流群,如果你是江西人可以加我微信 ruochuan12 私信 江西 拉你进群。

推荐阅读

1个月,200+人,一起读了4周源码
我读源码的经历

老姚浅谈:怎么学JavaScript?

我在阿里招前端,该怎么帮你(可进面试群)

················· 若川简介 ·················

你好,我是若川,毕业于江西高校。现在是一名前端开发“工程师”。写有《学习源码整体架构系列》多篇,在知乎、掘金收获超百万阅读。
从2014年起,每年都会写一篇年度总结,已经写了7篇,点击查看年度总结。
同时,活跃在知乎@若川,掘金@若川。致力于分享前端开发经验,愿景:帮助5年内前端人走向前列。

识别方二维码加我微信、拉你进源码共读

今日话题

略。欢迎分享、收藏、点赞、在看我的公众号文章~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/275484.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大学生电子设计大赛案例分析_为大学生设计问答平台—案例研究

大学生电子设计大赛案例分析Dealing with academic-related questions like picking a course, fulfilling a major requirement can be tedious and ineffective when you have to simultaneously balance school work, social activities, and focus on personal growth and …

最新最详细最简洁Eclipse调试PHP配置详解(Xdebug,Zend Debugger)

搬家注&#xff1a;该日志写于2011 年 04 月 07 日&#xff0c;Eclipse&#xff0c;PHP等版本号很多&#xff0c;更新也比较快&#xff0c;请注意文章中的版本。本文不一定帮您解决问题&#xff0c;但能给您一些解决问题的思路及一些概念。 最近开始做SRTP项目WebOS&#xff0c…

入门前端学习路线图【送书】

大家好&#xff0c;我是若川。记得点上方音频听小姐姐配音&#xff0c;超级好听。华章图书又赞助了书籍送福利给大家。本次送4本书的抽奖方式是&#xff1a;截止到9月6日&#xff08;周一&#xff09;20:00&#xff0c;在留言区留言任意内容。我会在留言区抽取「1位」关注我公众…

单选按钮设置为被选中状态_为什么要设置错误的按钮状态

单选按钮设置为被选中状态当正确的方法出错时 (When the right way goes wrong) Let’s say you want to create a click effect on an HTML button. The first idea that many people get is to do something that reproduces the feeling of the sound emitted by a real but…

「娃娃分享」-常见自校检分析实例.

自校检是许多软件的保护手段之一&#xff0c;对软件加个简单的壳再增加自校检在一定程序上可以抵挡住一大部分新手&#xff0c;不过&#xff0c;对许多人来说&#xff0c;这个保护已经很弱了。。下面讲几种常见的解决自校检方法&#xff0c;写的粗略&#xff0c;希望大家补充。…

用VC和MinGW导出dll的def和lib(a)文件

为什么80%的码农都做不了架构师&#xff1f;>>> 原文地址&#xff1a;http://zhangyafeikimi.iteye.com/blog/404580 有了dll文件需要导出def文件&#xff1a; pexports zlib1.dll > zlib1.def 有了dll和def文件&#xff0c;需要导出MinGW的.a文件&#xff1a;…

产品设计美学案例分析_美学在产品设计中的重要性

产品设计美学案例分析重点 (Top highlight)In one of my previous jobs, I had really interesting debates with the CEO regarding whether we should spend more time improving the way our app looks and feels. ‘How could he not care that the design is outdated?! …

即将到来的ECMAScript 2022标准

大家好&#xff0c;我是若川。周末分享一篇相对简单的文章。最近组织了源码共度活动&#xff1a;1个月&#xff0c;200人&#xff0c;一起读了4周源码&#xff0c;参与的小伙伴都表示收获很大。如果感兴趣可以点击链接扫码加我微信 ruochuan12。另外&#xff1a;昨天的推文入门…

c语言中二叉树中总结点,C语言二叉树的三种遍历方式的实现及原理

二叉树遍历分为三种&#xff1a;前序、中序、后序&#xff0c;其中序遍历最为重要。为啥叫这个名字&#xff1f;是根据根节点的顺序命名的。比如上图正常的一个满节点&#xff0c;A&#xff1a;根节点、B&#xff1a;左节点、C&#xff1a;右节点&#xff0c;前序顺序是ABC(根节…

动态库的创建与使用

1、动态库文件的创建 &#xff08;1&#xff09;编写源文件 &#xff08;2&#xff09;编译生成动态库 g -fPIC -shared -o libfile_operation.so file_operation.cpp 此编译过程分为两步&#xff0c;等同于下面的两个命令&#xff1a; g -c -fPIC file_operation.cpp …

ux设计中的各种地图_UX写作中的移情

ux设计中的各种地图Demetri Martin is a master of comedic situations. If you’ve never seen Demetri Martin是喜剧情境的大师。 如果你从未见过 him before, he has a sort of dry brand of observational humor, relying more on anecdotes than full stories, and often…

字符串搜索。HOJ1530 Compound Words。

stl set实现字符串搜索。。效率一般。(附二分搜索。) Compound WordsTime limit:1sec.Submitted:233Memory limit:32MAccepted:81Source: Waterloo ACM Programming Contest Sep 28, 1996 You are to find all the two-word compound words in a dictionary. A two-word compo…

字节3-1前端面试官自学Vue的正确姿势

大家好&#xff0c;我是若川。前不久和一个字节前端TL朋友聊天&#xff0c;说到大厂前端供需脱节的情况。特别是使用Vue框架的&#xff0c;因为简单易学好上手&#xff0c;但是能够深入理解的人并不多&#xff0c;大多都只停留在应用层面&#xff0c;缺乏更深层面的理解。尤其是…

苹果风格ui_苹果如何使Soft-UI成为未来

苹果风格ui重点 (Top highlight)Apple announced some pretty wild updates at WWDC 2020 today.苹果今天在WWDC 2020上宣布了一些相当疯狂的更新。 But technology aside, let’s focus on how their UI has changed. It went through the first bitmap representations, thr…

【数据结构】量子危机

问题 宇宙时间公元 5.55 亿年&#xff0c;由于某种原因两大联盟展开了激战&#xff08;maxingc 联盟采用了微子技术&#xff09;&#xff1a; 邪恶的 maxingc 联盟采集好了微子能&#xff0c;就要运输。Maxingc 联盟的领袖 xc 此时才发现&#xff0c;自己的军事基地中由微子发射…

android 自定义menu背景,Android编程实现自定义系统菜单背景的方法

本文实例讲述了Android编程实现自定义系统菜单背景的方法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;不多说&#xff0c;上图&#xff0c;见代码。package lab.sodino.menutest;import android.content.Context;import android.app.Activity;import android.os.Bu…

面试官问 async、await 函数原理是在问什么?

大家好&#xff0c;我是若川。这是 源码共读活动《1个月&#xff0c;200人&#xff0c;一起读了4周源码》 第四期&#xff0c;纪年小姐姐的第四次投稿。纪年小姐姐通过本次学习提早接触到generator&#xff0c;协程概念&#xff0c;了解了async/await函数的原理等。第四期是 学…

一步步优化JVM六:优化吞吐量[转]

2019独角兽企业重金招聘Python工程师标准>>> 原文&#xff1a;http://ganlv.iteye.com/blog/1571315 参考&#xff1a;http://www.myexception.cn/software-architecture-design/1455594.html 现代JVM是一个具有灵活适应各种应用能力的软件&#xff0c;尽管很多应用…

element-ui 网格_UI备忘单:列表与网格

element-ui 网格重点 (Top highlight)Grids or lists? That is the question we will look at in this cheat sheet. While they can be used anywhere in your site, we are going to look primarily at search results, catalogs and newsfeeds. Making this choice will de…

50行 koa-compose,面试常考的中间件原理原来这么简单?

大家好&#xff0c;我是若川。源码共读《1个月&#xff0c;200人&#xff0c;一起读了4周源码》 活动第五期是学习 koa 源码的整体架构&#xff0c;浅析koa洋葱模型原理和co原理中的koa-compose源码原理&#xff0c;阅读不到50行的koa-compose源码。这篇是izjing小哥哥的投稿。…