玩转Chrome DevTools,前端调试的秘诀

12,839 阅读9分钟

Chrome DevTools作为一名前端开发工程师的赖以生存的工具,日 常的断点调试,抓包http数据都只是基本操作。那么,你还知道他的一些高级用法吗?开发人员不可避免的需要维护别人写的代码,当你面对几十万行代码的大项目的时候,码海啊,茫茫啊,随波逐流,崩崩溃溃,怎么快速查找到想要的代码呢,作为一个专业的前端调试工程师,填坑小能手,今天我就从代码逆向分析开始,聊一聊chrome调试的一些高级用法。

1. 代码逆向分析

静态查找代码

全局查找

这个是大家一般都掌握的技巧 ,ctrl+shift+F打开全局搜索,搜索关键字一般是dom元素的id,class,name,或是页面中出现的具有唯一性的中文汉字,搜索到之后直接定位到代码。

查找绑定的DOM事件

适合原生代码和jquery开发的项目,以百度为例,顶部有个设置按钮,鼠标移上去,会弹出菜单,那么怎么找到弹出菜单的代码段呢?

  1. 在设置链接在点右键审查元素,在chrome elements面板右侧找到第3个页签event Listeners
  2. 在mouseover或mouseenter事件中会列出该元素绑定事件的代码行号
  3. 点击代码直接定位到相应的代码,然后加断点调试就可以了。

由于线上的代码都做了压缩混淆,需要点击pretty print格式化代码。

动态查找代码

调用堆栈(Call Stack)

堆栈是一个数据结构,每一个函数调用时都会将函数的指针和参数值保存在堆栈中,后进先出,最后调用的函数最先出栈。

堆栈对于调试的意义非常重大,我虽然不知道你从哪里来,但我知道你终将去向何处,只要在你执行的必经之路设置一个断点,就可以顺藤摸瓜找到你

先来看下堆栈的用法,编写如下测试代码:

function multiply(x, y) {
	debugger;
    return x * y;
}
function printSquare(x) {
    var s = multiply(x, x);
    console.log(s);
}
printSquare(5);

代码的整个执行流程如下:

  1. printSquare调用,将print Square的函数指针,和参数值5(即arguments)做为一项数据存放到call stack顶部
  2. 调用了multiply函数计算乘法,multiply函数指针,和两个参数5,5,被存放到call stack顶部。
  3. multiply函数调用完华(return),multiply函数从栈顶移除,调用console.log
  4. 因为console是内置对象,无法step into单步调试进去看内部代码, 实际上也是有入栈,console.log执行后即出栈,现在栈中只剩下最初的梦想printSquare孑然一身
  5. printSquare也出栈了,整个stack清净了。
    在call Stack面板可以看到函数调用的来龙去脉,快速切换到执行堆栈中的每一个函数

Dom 被修改时自动断点

我们以todomvc网站代码为例: todomvc.com/examples/vu… 添加一条todo记录,例如想看看删除元素时,vue dom diff是怎么工作的,我们知道点击删除后,这行li被删除了,但是究竟是哪一行代码在起作用,我们加个dom断点试一下,当dom节点被删除时,将会自动中断在修改dom的代码段

删除这条todo后,代码自动中断在vue虚拟dom的removeChild这一行,是不是很酷 ,但是这个堆栈的高度一共有28层楼,简直是摩天大厦啊,我对vue的dom diff 源码实在没有兴趣,那就直接坐电梯来到1楼好了

坐电梯来到1楼,看到这里是vue绑定dom事件的代码,也就是一切的起源,再往上看4楼就是具体的业务代码了

ajax 请求自动断点

有时你找不到事件绑定的代码,或者是有些功能在没有什么交互的情况下就发http请求调用了,这时ajax请求断点就派上用场了,在source 面板中xhr/fetch breakpoints中添加,可以捕获所有的url地址,也可以指定关键字捕获。

我刚添加了xhr断点之后,在编辑器中贴粘了一张图片,chrome就自动中断了,一不小心就看到了掘金的markdown编辑器上传图片和粘贴图片的前端源代码。看来这个webpack打包后函数名混淆的不彻底啊

异常时自动断点

这个功能正常情况下用处不大,普通的异常会在控制台显示,在控制台也能定位过去,可以定位过去之后再手工加断点, 但是对于catch 之后没有throw的代码,在控制台是看不到的,但是这个异常自动断点功能仍然能捕获到。

2. 在线调试、本地代理

如何才能在本地开发,不用上传到测试服务器或生产服务器,就能看到代码修改后的效果?如果我们用vue开发,vue-cli自带一个本地代理功能,可以把服务器的接口反向代理到本地的http服务,那么还有其它方法吗?我们来细数一下本地开发不用上传服务器就能生效代码的方法。

  1. vue-cli的本地代理功能,在配置文件devServer.proxy中配置反向代理,可以将后台接口代理到本机localhost。
  2. 自己搭建nginx反向代理,效果同第一条。
  3. 本地不需要任何http服务,直接访问硬盘上的html文件,利用cors跨域直接访问远程服务器,服务器端远程服务器设置响应头 Access-Control-Allow-Origin 的值 为 '*' ,注:此种方法不支持携带cookie。
  4. 使用fiddler AutoResponder功能,直接把远程服务器重定向到本地目录(需要编写一个正则表达式)
  5. 使用Chrome DevTools 的Overrides功能,把服务器的文件映射到本地,可以支持在Sources面板中修改文件直接生效,还能直持语法智能感知自动完成,比在console中写代码还方便。

以上五种方法各有优缺点,不详细展开,如果读者有兴趣我另外开一篇文章介绍。本文主要介绍第5种方法

在source面板二级页签Overrides页签中点击select folder for overrides,选择一个本地映射目录,然后顶部弹出一个确认提示一定要选择允许。

然后随便打开个网站改改代码试一下,例如,打开百度,在source面板点开主页面的html,加段alert,然后ctrl+s保存,文件图标会变成紫色,刷新下页面,弹出alert了,就这么简单,达到和tampermonkey插件一样的效果。哪个网站功能不爽,或者广告太碍眼了,那都不是事,随便写行代码改掉他。

当然,最主要的还是开发起来贼方便,谁用谁知道,尤其是遇到那些没有测试环境的功能,只能在生产线上调试的场景。如果没有本地代理映射,只能找运维更新代码去看效果了。

3. 性能优化分析

查找引起性能瓶颈的函数

Performance面板的 call tree 可以查看每个函数的执行时间,非常方便的找到性能瓶颈,我们先来编写一段有性能问题的代码测试一下。

setInterval(function slowFunc(){
var arr=[];
for(var i=0;i<1000;i++){
arr.push(i);
arr.sort();
}
},50)

运行之后,打开performance面板点击录制,开始监控,再点停止,在call tree 中可以以树状结构展示每个函数和子函数的执行时间,我们一眼就看到名为slowFunc的函数执行时间最长,达到786ms,点击函数名即可跳转到相应的代码。

代码覆盖率检测

项目时间久了,会有很多冗余代码是从来不会执行的,或是需要做首屏加载优化,想把首屏用不到的js和css 代码抽取出来做异步加载,使用chrome自带的coverage检测工具可以很方便的看到哪些代码被执行了,红色表示未被执行的代码。做首屏优化时可以抽取出来做异步加载,如果你把所有的用例都跑完了,这行代码还是红色的,则可以从容的删除这些红色的代码。

code coverage面板默认是不显示的,需要在more tools 菜单中打开

4. 移动端真机调试

移动端开发经常遇到一些真机上运行会出问题,pc端浏览器却无法重现的问题,这就需要真机调试,如果是iphone,可以用usb 连接 mac 下的safari浏览器直接调试。其实android手机的真机调试其实更加强大,完爆苹果,毕竟safari的调试功能跟chrome相比简直弱爆了,让那些喜欢用苹果本的前端开发同学羡慕去吧。

但是很多同学配置不好usb真机调试,因为搞好这个简直比从零开始搭建webpack环境还难,步骤如下,缺一不可

  1. android手机必须安装adb interface driver,手机连了usb即使能copy文件了,也不代表驱动安装好了,有些手机助手会自带这个驱动,如果不行,可到官网下载http://adbdriver.com/
  2. 在手机设置中的开发人员选项中,打开 usb调试功能
  3. 用usb 线连接手机,每次连接usb 调试都会弹一个确认框要确认。
  4. 在手机上用chrome浏览器打开要调试的网站,以打开github.com网站为例,一定要用独立的chrome(在各大应用市场安装),有些手机自带的浏览器可能关闭了webkit远程调试功能你只能望洋兴叹。
  5. 在地址栏输入 chrome://inspect/ ,如果前面几步都没问题,将会出现可调试的页面列表,点击inspect即可打开调试页面。
  6. 最重要的一步,需要翻墙一次,可以用blue灯,因为首次调试会连接google的官方网站,国内无法访问会中断调试无法进入到下一步。以后只要不重装浏览器都不需要再次翻墙了。
  7. inspect之后便会出现调试面板,就可以和普通的pc端页面一样调试了。

小结

工欲善其事,必先利其器,chrome devtools能够让你用各种方法快速找到目标代码,并提供了性能分析,网络分析等强大能力,用好了绝对能事半功倍,告别996。

最后,推荐一下我的开源项目:

webcontext --一款能够让你编写最少代码的功能强大的node.js web框架:

github.com/windyfancy/…