当前位置: 首页 > news >正文

【前端必看】极大提高开发效率的网页 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进行了简单的介绍,在其文档介绍中发现,这几个容器有个共同点是&#xff1…...

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视频编解码目前有两种方案: 一是使用专用编解码芯片&#xff0…...

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的。其表达式可以接受“…...

docker-容器数据卷

Docker挂载主机目录访问如果出现cannot open directory.:Permission denied 解决办法:在挂载目录后多加一个--privileged=true参数即可; 一、介绍 卷就是目录或文件,存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能绕过Union Fil…...

【C++】类和对象补充知识点

🏖️作者:malloc不出对象 ⛺专栏:C的学习之路 👦个人简介:一名双非本科院校大二在读的科班编程菜鸟,努力编程只为赶上各位大佬的步伐🙈🙈 目录前言一、再谈构造函数1.1 构造函数体赋…...

路径规划-人工势场法

一.基本思想 目标点对机器人产生吸引力,障碍物对机器人产生排斥力; 所有力的合成构成机器人的控制律 二. 主要步骤 1.构建人工势场 目标点:吸引势场 障碍物:排斥势场 2.根据人工势场计算力 对势场求偏导 3.计算合力 计…...

20230304学习笔记

1、Mybatis #{}和${}的区别是什么 a、#{}是预编辑处理、是占位符,${}是字符串拼接符。 b、#{}替换为?号,用PreparedStatement来赋值,${}直接替换变量的值,用Statement赋值。 c、#{}在DBMS中、自动加入单引号&#…...

[数据集][VOC][目标检测]河道垃圾水面漂浮物数据集目标检测可用yolo训练-1304张介绍

数据集格式:Pascal VOC格式(不包含分割路径的txt文件和yolo格式的txt文件,仅仅包含jpg图片和对应的xml) 图片数量(jpg文件个数):1304 标注数量(xml文件个数):1304 标注类别数:1 标注类别名称:["trash"] …...

JavaWeb--JSP案例

JSP案例8 案例8.1 环境准备8.1.1 创建工程8.1.2 创建包8.1.3 创建表8.1.4 创建实体类8.1.5 准备mybatis环境8.2 查询所有8.2.1 编写BrandMapper8.2.2 编写工具类8.2.3 编写BrandService8.2.4 编写Servlet8.2.5 编写brand.jsp页面8.2.6 测试8.3 添加8.3.1 编写BrandMapper方法8.…...

推荐系统1--Deepfm学习笔记

目录 1 keras实现Deepfm demo 2 deepctr模版 3 其他实现方式 ctr_Kera 模型 数据集 预处理 执行步骤 4何为focal loss 参考 1 keras实现Deepfm 假设我们有两种 field 的特征,连续型和离散型,连续型 field 一般不做处理沿用原值,离散型一…...

javaDoc生成方式

javaDoc生成方式 命令行生成 在cmd控制台窗口上找到需要生成文件的路径,然后执行命令。 # javadoc -encoding UTF-8 -charset UTF-8 文件名 javadoc -encoding UTF-8 -charset UTF-8 Doc.java这样就生成完成了。 测试Doc.java文件 package com.jiang.base;/***…...

Armv9 registers

A64指令集包括访问system registers编码空间的指令。这些指令有: Access to System registers, including the debug registers, that provide system control, and system status information.Access to Special-purpose registers such as SPSR_ELx, ELR_ELx, an…...

套接字实现TCP

套接字 套接字的意义就是客户端与服务器进行双向通信的端点,如果有不理解点上面套接字三字更近距离了解套接字。 网络套接字与客户连接的特定网络有关的服务端口号,这个端口号允许linux进入特定的端口号的连接转到正确的服务器进程。 套接字通信的建立过…...