【前端必看】极大提高开发效率的网页 JS 调试技巧
大家好,我是前端西瓜哥。本文讲解如何使用浏览器提供的工具进行 JS 代码的断点调试。
debugger
在代码中需要打断点的地方,加上 debugger
,表示一个断点。浏览器代码执行到该位置时,会停下来,进入调试模式。
示例代码:
function a() {let a_var = 'a';b(a_var);
}function b(a_var_from_a) {debugger;console.log(global_var);let b_var = 'b';c();
}function c() {let c_var = 'c';
}let module_var = 'module';
var global_var = 'global';a();
整体就是调用 a,然后 a 调用 b,b 调用 c,然后有各种作用域的变量。
记得打开开发者工具面板,没打开的话,debugger 会静默失败。
下面是断点后的样子。
现在是 a 函数调用了 b 函数,b 函数调用的时候用 debugger
加了个断点,于是我们就停在这里了。
此时上下文状态和调用站会保留着,方便我们排查是什么分支导致变量状态错误,比如一个错误的条件判断,让一个为 null 的变量没能变成一个普通对象,导致访问它的属性报错。
手动打断点
在对应的行号点一下就可以了,相当于加了个 debugger 关键字。
刷新页面后,手动打的断点还会保留。
调用栈信息
首先是函数调用栈信息。
调用的起始端是一个匿名函数,没有名字的函数都会显示 anonymouse
,这里是 script 最外层的直接调用,所以没有名字。我本人建议多给匿名函数起个名字,可读性会更好。但如果你有起名困难症,不起也好。
匿名函数,然后调用了函数 a,函数 a 再调用了函数 b,然后停下了。之后还会调用 c。
看到 b 旁边的蓝色箭头没,它表示我们 正在观测哪个函数的上下文,默认会选择栈顶。
你可以用光标选择你要观测的函数下的变量,并且会高亮对应的代码。
作用域
我们看看某个函数的函数作用域的上下文。
找到 Scope 这个标签页,目前我们可以看到有三种类型:Local、Script 和 Global。
首先是 Local,本地作用域。这里对应 b 函数的上下文,可以看到(1)传入的变量,(2)函数内部声明的变量,以及 (3)this 值。
然后是 Script,表示一个模块文件的最外层变量,和全局变量不同,只能被模块文件内的文件的代码访问。
最后是 Global,全局作用域。
再补充一个比较常见的闭包作用域。如果一个函数是通过闭包产生的,那在 Local 和 Script 还会有一个闭包作用域。
在函数中访问一个变量,其实就是沿着这条链路去查找最先找到的那个,如果找不到就会拿到 undefined。
当然除了这些,还有不少,比如块作用域(Block)、捕获作用域(Catch Block)、Eval 作用域、With 块作用域等,篇幅原因,不一一介绍了。
执行下一步
实际我们还要看看代码是否如预期进入我们希望的分支并拿到正确的值,所以需要 让代码一点点执行下去,观察状态的变化。
浏览器提供了各种执行下一步代码的方式。
我们一个个过一遍。
Resume 恢复脚本执行
首先是最左边这个 矩形+三角形 的蓝色按钮,它表示 结束当前断点,恢复脚本运行。
但如果往下执行,又遇到一个断点,那又会进入调试模式。
于是在长循环的情况下,就出不来了(悲)。
这时候恼羞成怒的西瓜哥有个办法,长按这个按钮,然后出现一个停止按钮,点它会 结束所有的断点。
或者更常见的做法是,只在特定判断条件下的打断点,比如:
todoItems.forEach(item => {// item 不可能为 null,我们来看看发生甚么事了if (!item) {debugger;}// ...
})
Step over 跳过下一个函数
然后是跳过下一个函数。就是遇到下一个要执行的函数,就不进去了,执行完它继续往下运行。
为什么要跳过函数?因为函数里面有很多代码,或者里面又调用了其他函数,要走好久才能回到当前函数。
如果我们只是想看当前函数的完整逻辑,那就跳过其下的函数执行。
Step into 进入下一个函数
如果走着走着遇到一个函数,进入这个函数。
注意,浏览器环境自带的 api 方法是进不去的。
Step out 跳出当前函数
如果你不想再看当前函数的执行了,想回到调用它的函数,就可以选择这个方式。
Step 下一步
就是普通的下一步,它会严格遵守代码的执行顺序,比较常用。
Step into 和 Step 的区别
Step into 和 Step 在大体的表现上有些相同,遇到函数是会进入函数内部的,但在异步代码下,行为有一些不同。
Step into 在遇到一个异步代码的回调函数,会直接挂起并让后面的同步代码继续跑,直到这个异步函数被执行,然后进入这个函数。
而 Step 则符合代码的执行顺序,先执行后面的同步代码,然后再执行异步函数。
我们用一个实例演示一下。代码为:
window.onclick = () => {debugger;setTimeout(() => {console.log('inside');console.log('p1', performance.now() / 1000);}, 2000);console.log('p2', performance.now() / 1000);console.log('p3', performance.now() / 1000);
};
Step into 的表现:
可以看到,Step into 会等待异步函数被执行,才进入到函数内部,然后停在它的首行。
然后是 Step:
Step 遵循正常的代码执行过程顺序:先走完同步代码,然后再进入异步代码。
直接跳到某一行
我们可能想直接跳到中间的一连串逻辑,直接走到后面的某一行,对此我们可以手动跳转。
具体做法是行号右键选择 continue to here
。
需要注意,这个地方必须是和当前位置在同一个函数下,否则会等价于执行了 Resume。
其他
关闭断点功能
关闭断点功能(deactivate breakpoint)。
开启这个,断点在打开开发者工具的条件下无效。
上一篇文章西瓜哥说了一个用定时器不断执行 debugger 的方式,防止别人点点点看代码是怎么执行的。但这只能防小白,我们把这个开了就无视 debugger 关键字了。
报错时断点
代码报错时,我们希望知道报错那瞬间的上下文。
此时我们可以开启这个功能,在报错且没有被捕获时,浏览器会给你打一个断点,然后你可以看看哪个变量出了问题。
还可以勾选这个 Pause on caught exceptions
,效果是错误被捕获时,打断点:
结尾
光说不练假把式,西瓜哥建议你自己尝试一番。
编程是一个实操性很强的学科,要自己动手调试,这样才能更好地理解掌握。
我是前端西瓜哥,欢迎关注我,学习更多前端知识。
相关文章:

【前端必看】极大提高开发效率的网页 JS 调试技巧
大家好,我是前端西瓜哥。本文讲解如何使用浏览器提供的工具进行 JS 代码的断点调试。 debugger 在代码中需要打断点的地方,加上 debugger,表示一个断点。浏览器代码执行到该位置时,会停下来,进入调试模式。 示例代码…...

【春招面经】视源股份前端一面
前言 本次主要记录一下视源股份CVTE前端一面 (3.3下午4点15) 文章目录前言本次主要记录一下视源股份CVTE前端一面 (3.3下午4点15)问题总结介绍一下项目的来源以及做这个项目的初衷一直监听滚动,有没有对性能产生影响&a…...

插件化开发入门
一、背景顾名思义,插件化开发就是将某个功能代码封装为一个插件模块,通过插件中心的配置来下载、激活、禁用、或者卸载,主程序无需再次重启即可获取新的功能,从而实现快速集成。当然,实现这样的效果,必须遵…...

tftp、nfs 服务器环境搭建
目录 一、认识 tftp、nfs 1、什么是 tftp? 2、什么是 nfs? 3、tftp 和 nfs 的区别 二、tftp的安装 1、安装 tftp 服务端 2、配置 tftp 3、启动 tftp 服务 三、nfs 的安装 1、安装 nfs 服务端 2、配置 nfs 3、启动 nfs 服务 一、认识 tftp、…...

汇编系列03-不借助操作系统输出Hello World
每天进步一点点,加油! 上一节,我们通过汇编指令,借助操作系统的系统调用实现了向标准输出打印Hello world。这一节我们打算绕过操作系统,直接在显示屏幕上打印Hello world。 计算机的启动过程 当我们给计算机加电启…...

TPU编程竞赛系列|算能赛道冠军SO-FAST团队获第十届CCF BDCI总决赛特等奖!
近日,第十届中国计算机学会(CCF)大数据与计算智能大赛总决赛暨颁奖典礼在苏州顺利落幕,算能赛道的冠军队伍SO-FAST从2万余支队伍中脱颖而出,获得了所有赛道综合评比特等奖! 本届CCF大赛吸引了来自全国的2万…...

【C++】AVL树,平衡二叉树详细解析
文章目录前言1.AVL树的概念2.AVL树节点的定义3.AVL树的插入4.AVL树的旋转左单旋右单旋左右双旋右左双旋AVL树的验证AVL树的删除AVL树的性能前言 前面对map/multimap/set/multiset进行了简单的介绍,在其文档介绍中发现,这几个容器有个共同点是࿱…...

C/C++开发,无可避免的多线程(篇四).线程与函数的奇妙碰撞
一、函数、函数指针及函数对象 1.1 函数 函数(function)是把一个语句序列(函数体, function body)关联到一个名字和零或更多个函数形参(function parameter)的列表的 C 实体,可以通过返回或者抛…...
elisp简单实例: taglist
从vim 转到emacs 下,一直为缺少vim 中的tablist 插件而感到失落. 从网上得到的一个emacs中的taglist, 它的功能很简陋,而且没有任何说明, 把它做为elisp的简单实例,供初学者入门倒不错,我给它加了很多注释,帮助理解, 说实话,感觉这百行代码还是挺有深度的,慢慢体会,调试才会有收…...
Azure AI基础到实战(C#2022)-认知服务(3)
目录 OpenFileDialog 类上一节代码的API剖析ComputerVisionClientExtensions.ReadAsync MethodReadHeaders ClassReadHeaders.OperationLocation Property探索ReadHeaders加上调试代码可用于 Azure 认知服务的身份验证标头使用单服务订阅密钥进行身份验证使用多服务订阅密钥进行…...

aws apigateway 使用restapi集成lambda
参考资料 代理集成,https://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-lambda.html非代理集成,https://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/getting-started-…...

HTML基础
HTML 基础 文章目录HTML 基础列表标签无序列表有序列表自定义列表表格标签表格基本标签表格基本结构表格完整结构:合并行和合并列表单标签input 系列标签属性标签text 标签radio 标签 单选框file 标签 文件选择button 标签 按钮input系列标签总结button按钮标签sele…...
ThreadPoolExecutor参数 keepAliveTime allowCoreThreadTimeOut
/*** Timeout in nanoseconds for idle threads waiting for work.* Threads use this timeout when there are more than corePoolSize* present or if allowCoreThreadTimeOut. Otherwise they wait* forever for new work.*/ private volatile long keepAliveTime;等待工作的…...
什么是Hibernate框架?
简单介绍:Hibernate框架是当今主流的java持久层框架之一,是一个开放源码的ORM(Object Relational Mapping,对象关系映射)框架,它对JDBC进行了轻量级的封装,使得JAVA开发人员可以使用面向对象的编…...

指针面试笔试题练习
前言 🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨ 🐻推荐专栏: 🍔🍟🌯 c语言进阶 🔑个人信条: 🌵知行合一 🍉本篇简介:>:介绍c语言中有关指针更深层的知识. 金句分享: ✨星光…...

docker(三)仓库的搭建、官方私有仓库的加密和认证
文章目录一、docker仓库二、仓库Registry工作原理三、搭建本地私有仓库四、配置镜像加速器五、私有仓库的加密认证1.非加密下上传拉取2.insecure registry3.仓库加密4.仓库认证一、docker仓库 什么是仓库 Docker 仓库是用来包含镜像的位置,Docker提供一个注册服务器…...

FPGA实现SDI视频编解码 SDI接收发送,提供2套工程源码和技术支持
目录1、前言2、设计思路和框架SDI接收SDI缓存写方式处理SDI缓存读方式处理SDI缓存的目的SDI发送3、工程1详解4、工程2详解5、上板调试验证并演示6、福利:工程代码的获取1、前言 FPGA实现SDI视频编解码目前有两种方案: 一是使用专用编解码芯片࿰…...

Android 基础知识4-3.5 RadioButton(单选按钮)Checkbox(复选框)详解
一、RadioButton(单选按钮) 1.1、简介 RadioButton表示单选按钮,是button的子类,每一个按钮都有选择和未选中两种状态,经常与RadioGroup一起使用,否则不能实现其单选功能。RadioGroup继承自LinearLayout&a…...

用代码实现解析解的方式求解_梯度下降法思路_导函数有什么用_接23节---人工智能工作笔记0026
这里24节,25节,介绍了一下人工智能高等数学要学习的一些内容,初步了解了一下,微积分中用到的知识~微分~以及导数这里... 然后接着23节,我们还是继续,走人工智能的主线,先把整体的人工智能的内容学习一遍,然后再去回去看数学知识更有目的性. 然后首先来回顾一下,这里机器学习,其…...

大数据ETL开发之图解Kettle工具
详细笔记参考:https://blog.csdn.net/yuan2019035055/article/details/120409547以下只是简单记录一下我学习过程中的心得3.1.5 JSON输入JSONPath 类似于 XPath 在 xml 文档中的定位,JsonPath 表达式通常是用来路径检索或设置Json的。其表达式可以接受“…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...

Golang——6、指针和结构体
指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...

消防一体化安全管控平台:构建消防“一张图”和APP统一管理
在城市的某个角落,一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延,滚滚浓烟弥漫开来,周围群众的生命财产安全受到严重威胁。就在这千钧一发之际,消防救援队伍迅速行动,而豪越科技消防一体化安全管控平台构建的消防“…...
面试高频问题
文章目录 🚀 消息队列核心技术揭秘:从入门到秒杀面试官1️⃣ Kafka为何能"吞云吐雾"?性能背后的秘密1.1 顺序写入与零拷贝:性能的双引擎1.2 分区并行:数据的"八车道高速公路"1.3 页缓存与批量处理…...
第八部分:阶段项目 6:构建 React 前端应用
现在,是时候将你学到的 React 基础知识付诸实践,构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段,你可以先使用模拟数据,或者如果你的后端 API(阶段项目 5)已经搭建好,可以直接连…...

企业大模型服务合规指南:深度解析备案与登记制度
伴随AI技术的爆炸式发展,尤其是大模型(LLM)在各行各业的深度应用和整合,企业利用AI技术提升效率、创新服务的步伐不断加快。无论是像DeepSeek这样的前沿技术提供者,还是积极拥抱AI转型的传统企业,在面向公众…...