Chrome 常用调试方法探究

196 阅读6分钟

Chrome 是一款浏览器,对前端工程师来说也是一款调试利器,下面的几个功能是我在工作中最常用到的几个,下面逐个介绍。

断点

添加断点可以直接在代码中硬编码,增增加一行debugger 表达式即可,代码执行到此处会断到此处:

image.png 在 VSCode 中,黄色下划线表示警告。一般不会使用此方式,因为此方式跟 console.log 并没有明显的优势,甚至还不如前者简单,因为你用完之后还得删了,不然代码是不可用的。

还有一种方式是直接在 devtools 中的 source tab 中找到源码,一般是通过 console.log 输出后,点击控制台右侧的文件名,可以在 Sources tab 中看到源码,点击左下角格式化之后,在代码左侧行号出点击标记断点,即可调试,如下图:

image.png 断点后,图中红色部分的按钮,从左向右依次的含义:

  • 继续执行 :点击后,断点将直接执行到下一个断点处。
  • setp over :如果当前断点所在位置不是函数,则跟 step 一样,执行到下一行;如果是函数,则会跳过该函数继续执行到下一行。
  • setp into :如果没有异步代码,则跟 setp 一样,执行到下一行;如果有异步代码,但它会进入到异步代码的内部第一行。
  • step out :点击后,跳出当前函数。
  • setp :执行下一行同步代码,跟 step into 不一样, 它会跳过异步代码的执行;如果当前断点在函数处的话,会进入到函数调用内部第一行。
  • 暂时停用/激活断点 :首次点击后会临时禁止断点功能,就像没有打断点一样代码不会停止执行,下方的 Breakpoints 中的断点会整体置灰:

image.png

image.png

  • 将断点停在报错处 点击高亮后启用,代码将会自动停止到任何 throw error 的地方,无论是否是被 catch 住,也无论是 http 错误还是什么错误。注意必须把下面的Pause on caught exceptions 勾选才行,不勾选等于无效:

image.png

此功能最好是在代码执行一遍完成后,页面载入完成后,开始交互的时候打开,否则可能一进入页面就会报错,包括 React 中的合法报错等,导致无法正常加载页面。

直接放一张官方断点的图:

image.png 上图中上述的按钮下面有一系列的 toggle  三角号可以点击,依次为:

  • Watch 可以监测断点处的任何可访问到的上下文变量以供显示,如果变量不存在或者无法访问,如访问 a.b.c 的时候,a 不存在,那么会显示不可用。当断点断的时候,该位置输入的变量会自动显示,而不用鼠标悬浮上去(像上面官方图一样)查看变量,很方便。
  • Breakpoints 表示已经有的断点。checkbox 打勾的是可用的断点,未打勾的是暂时忽略的断点(可以临时打勾或者取消掉)。

image.png

当前执行到的断点,背景是黄色的。

  • Threads 表示当前调用的文件线程,当期页面 JavaScript 线程表示为 Main 中。此部分一般用不到,只是用来调试Web Worker 比较有用,也可以用来在当前页面调试 Chrome 浏览器插件。
  • Scope 显示当前断点处的可访问到的变量值。因为 JavaScript 的闭包和调用栈的特性,会显示很多闭包中的变量:

image.png

  • Call Stack 即函数的调用栈,最顶层的是最近的调用,可以通过点击不同的函数在其之间来回跳。需要注意的是,跳转的时候不会真的再次执行到那个位置,只是方便你查看那个位置的闭包变量。

UI 断点

有些情况下,你不知道或者无从定位一个 UI 问题为什么会这么变化。比如,你的同事写了一个 hover 到按钮上之后,按钮颜色变化的代码。你需要为这个逻辑添加新的逻辑,但是你并不知道他的代码逻辑写在哪个文件(他没有交接工作就休假了,可恶!)。

你发现 hover 到按钮上的时候,按钮会增加个 class 类名,于是你可以使用 dom 断点进行调试,在 Elements tab 中,你需要检查的那个元素上右键:

image.png UI 断点可以将代码停到你指定的 UI 事件所执行的代码发生之前的那一刻,UI 事件包括:

  • 子树修改:如果子树有任何修改,如增加、属性变更等,会将代码断到该逻辑即将执行的地方。
  • 属性修改:如果当前右键的元素有任何修改,会将代码断到该逻辑即将执行的地方。
  • 节点移除:如果当前右键的元素移除,会将代码断到该逻辑即将执行的地方。

举个例子,飞书文档中,如果 block 聚焦,则会在节点上添加一个 focus 类名:

image.png

image.png 此时就可以使用 attribute modifications 进行断点:

image.png 当然,默认情况下线上代码是压缩后的,点击左下角的 {} 就会格式化:

image.png 格式化之后,Chrome 会新建一个 tab,在文件后面加上 :formatted :

image.png

需要注意的是,如果你右键的元素在变更的时候是父节点变更,如父节点整体移除,则 UI 断点不会执行。

Overwrite

Charles 有类似的功能叫 Map js(没记错的话),ProxyMan 的类似功能叫 Map Local,都是一个意思。

有时候,因为上线/测试链路比较长(尤其是编辑器这种基础工具组件,需要发包),想快速验证一个 case 的时候就会比较麻烦,因此可以使用 Chrome 的 Overwrite 功能。

此功能类似于 Charles 的 Map js 功能,即可以将本地文件作为页面的请求进行响应,你需要先在 Sources 中启用该功能,当然,如果没有指定本地的文件存储的位置,需要先让你指定位置才行:

image.png 此时 Chrome 会提醒你需要本地该路径的完全访问权限,同意即可:

image.png

image.png 然后转到 Network tab,选择一个资源,如 css/js,我这里选择的是 js:

image.png 注意,如果没有在 Sources 中启用 Overwrite 的话,这里是不会显示 Save for overrides 的。

之后就可以各种修改该文件,然后刷新页面查看修改后的效果了。

需要注意的是,如果 js 文件请求后有时间戳,则 Overwrite 不会生效,因为 Chrome 是使用严格的路径匹配来 map 文件的。

Snippet

准确说,这个不算是「调试方法」,但是平常有个代码验证的片段,我也会存到这个里面,相当于一个 Sublime(可以对输入过的变量进行自动补全),挺好用的:

image.png

Filesystem

该功能跟上面几个在同一个位置,用来实时同步浏览器中的修改到本地文件系统。该功能适合一个简单的 HTML Web 服务,如 Express 这种服务端返回 js/css/html 等的本地调试时候用。

但是该功能官方明确说了,不适合 React App。因为现在基本项目都是 React、Vue 等的现代框架构建的,因此此功能用的较少,这里仅放个官方截图:

image.png