【前端必看】极大提高开发效率的网页 JS 调试技巧

news2024/11/16 0:31:14

大家好,我是前端西瓜哥。本文讲解如何使用浏览器提供的工具进行 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,效果是错误被捕获时,打断点:

结尾

光说不练假把式,西瓜哥建议你自己尝试一番。

编程是一个实操性很强的学科,要自己动手调试,这样才能更好地理解掌握。

我是前端西瓜哥,欢迎关注我,学习更多前端知识。

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

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

相关文章

java内存模型的理解

java内存模型的理解并发问题产生的源头缓存导致的可见性问题线程切换导致的原子性问题编译优化带来的有序性问题小结Java内存模型: 解决可见性和有序性问题Java内存模型与JVM内存模型的区别volatile关键字Happens-Before规则小结思考题参考并发问题产生的源头 缓存导致的可见性…

【Verilog】——Verilog简介

目录 1.简介 2.什么是HDL以及HDL的功能 3.Verilog和C语言的比较 4.Verilog的用途 5.数字系统的抽象层次 1.系统级 2.算法级 3.RTL级(寄存器变换级) 6.数字系统抽象层级 7.自顶向下的结构化设计方法 8.Verilog建模 9.Verilog概述 10.Verilog模块的基本…

Django学习17 -- ManytoManyField

1. ManyToManyField (参考:Django Documentation Release 4.1.4) 类定义 class ManyToManyField(to, **options)使用说明 A many-to-many relationship. Requires a positional argument: the class to which the model is related, which w…

推导部分和——带权并查集

题解: 带权并查集 引言: 带权并查集是一种进阶的并查集,通常,结点i的权值等于结点i到根节点的距离,对于带权并查集,有两种操作需要掌握——Merge与Find,涉及到路径压缩与维护权值等技巧。 带…

用Python批量重命名文件

案例 今天,我们来整理文件夹中的文件,给某个文件夹下的所有文件重新命名。要求是给所有文件按照修改时间,按顺序在文件名前面加上编号。比如将文件资料.xlsx重命名为1. 资料.xlsx import osdef Get_modify_time(file):return os.path.getmtime(file) #获取文件修改时间path…

vue3的v-model指令

1. 普通input输入框双向绑定 <template><!-- 1. 普通input输入框双向绑定 --><!-- 其实等价于&#xff1a;<input :modelValue"title" update:modelValue"newTitle>titlenewTitle"/> --><input type"text" v-mod…

Junit测试框架

一、简介 Junit框架是一个开源的Java语言单元测试框架&#xff0c;Java方向使用最广泛的单元测试框架&#xff0c;使用Java开发者都应该学习Junit并能掌握单元测试的编写。 对于Junit和Selenium的关系&#xff1a;通俗点来说Selenium如果比喻为灯泡&#xff0c;那么Junit就是电…

【蓝桥杯集训15】求最短路存在负权边——spaf算法(2 / 4)

——SPFA 算法是 Bellman-Ford算法 的队列优化算法的别称 单源最短路&#xff0c;且图中没有负环就可以用spfa 目录 spaf求最短路模板 852. spfa判断负环 341. 最优贸易 - 3305. 作物杂交 - spaf求最短路模板 只有当一个点的前驱结点更新了&#xff0c;该节点才会得到…

操作系统——16.时间片轮转、优先级、多级反馈队列算法

这篇文章我们来看一下进程调度算法中的时间片轮转、优先级、多级反馈队列算法 目录 1.概述 2.时间片轮转调度算法&#xff08;RR&#xff0c;Round-Robin&#xff09; 3.优先级调度算法 4.多级反馈队列调度算法 5.分析对比 1.概述 首先&#xff0c;我们来看一下这篇文章…

计算机网络整理

TCP与UDP 介绍 HTTP&#xff1a;&#xff08;HyperText Transport Protocol&#xff09;是超文本传输协议的缩写&#xff0c;它用于传送WWW方式的数据&#xff0c;关于HTTP协议的详细内容请参考RFC2616。HTTP协议采用了请求/响应模型。 TCP:&#xff08;Transmission Contro…

[YOLO] yolov3、yolov4、yolov5改进

yolov3网络结构图&#xff1a; Yolov3的三个基本组件&#xff1a; &#xff08;1&#xff09;CBL&#xff1a;Yolov3网络结构中的最小组件&#xff0c;由ConvBnLeaky_relu激活函数三者组成。 &#xff08;2&#xff09;Res unit&#xff1a;借鉴Resnet网络中的残差结构&#x…

docker 入门篇

docker为什么会出现&#xff1f; 一款产品&#xff1a;开发---->运维&#xff0c;两套环境&#xff01;应用环境&#xff0c;应用配置&#xff01; 常见问题&#xff1a;我的电脑可以运行&#xff0c;版本更新&#xff0c;导致服务不可用。 环境配置十分的麻烦&#xff0c;…

RL笔记:基于策略迭代求CliffWaking-v0最优解(python实现)

目录 1. 概要 2. 实现 3. 运行结果 1. 概要 CliffWalking-v0是gym库中的一个例子[1]&#xff0c;是从Sutton-RLbook-2020的Example6.6改编而来。不过本文不是关于gym中的CliffWalking-v0如何玩的&#xff0c;而是关于基于策略迭代求该问题最优解的实现例。 CliffWalking-v0的…

Promise-异步回调

1.理解Promise promise是ES6提出的异步编程的新的解决方案&#xff0c;通过链式调用解决ajax回调地狱 从语法上看&#xff0c;promise是一个构造函数&#xff0c;自己身上有all、reject、resolve方法&#xff0c;原型上有then、catch方法 从功能上看&#xff0c;Promise对象用…

BloomFilter原理学习

文章目录BloomFilter简单介绍BloomFilter中的数学知识fpp(误判率/假阳性)的计算k的最小值公式总结编程语言实现golang的实现[已知n, p求m和k](https://github.com/bits-and-blooms/bloom/blob/master/bloom.go#L133)参考BloomFilter简单介绍 BloomFilter我们可能经常听到也在使…

瑞吉外卖——day2

目录 一、新增员工 二、查询分页数据 三、启用、禁用员工账户、编辑员工信息 一、新增员工 点击左上角新增员工 页面如下&#xff1a; 我们随便填数据 &#xff0c;点击保存&#xff0c;请求的地址如下 返回前端可以看到请求方式为Post 在employeeController中编写对应的代…

Elasticsearch:图片相似度搜索的 5 个技术组成部分

作者&#xff1a;Radovan Ondas&#xff0c;Bernhard Suhm 在本系列博文的第一部分中&#xff0c;我们介绍了图像相似度搜索&#xff0c;并回顾了一种可以降低复杂性并便于实施的高级架构。 此博客解释了实现图像相似性搜索应用程序所需的每个组件的基本概念和技术注意事项。 学…

Python采集本地二手房,一键知晓上万房源信息

前言 大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 所以今天教大家用Python来采集本地房源数据&#xff0c;帮助大家筛选好房。 话不多说&#xff0c;让我们开始愉快的旅程吧~ 更多精彩内容、资源皆可点击文章下方名片获取此处跳转 本文涉及知识点 采集基本流程 requests 发送…

【Java】Spring Boot整合WebSocket

【Java】Spring Boot整合WebSocket WebSocket简介 WebSocket是一种协议&#xff0c;用于实现客户端和服务器之间的双向通信。它可以在单个TCP连接上提供全双工通信&#xff0c;避免了HTTP协议中的请求-响应模式&#xff0c;从而实现更高效的数据交换。WebSocket协议最初由HTM…

【计算几何】贝塞尔曲线 B样条曲线简介及其离散化 + Python C++ 代码实现

文章目录一、贝塞尔曲线二、B样条曲线三、Python 代码实现B样条曲线离散化四、C 代码实现B样条曲线离散化4.1 主要代码4.2 其余类4.3 离散效果展示&#xff08;在CAD中展示&#xff09;本文只做简介&#xff0c;关于贝塞尔曲线和B样条曲线的详细介绍&#xff0c;请参考&#xf…