要验证我们编写的代码是否符合预期,我们需要在浏览器页面中进行调试。
# 浏览器(Chrome)调试
浏览器中调试功能又多又方便,但我们更主要是在 Chrome 下进行调试,先看看 Chrome 提供的开发者工具:
Elements、Console、Sources、Network 这种前面也介绍过了,剩下的功能在性能调试的时候会用的多一些:
Performance
:查看页面在浏览器运行时的性能表现,如 CPU\GPU 执行时间与内存占用等Memory
:可进行内存查看和分析Application
:会列出所有的资源,包括 Database 和 LocalStore 等,可以对存储的内容编辑和删除Security
:查看网站的安全性,有效证书等Audits/Lighthouse
:会针对目前网页提出若干条优化的建议,包括网络加载性能、界面性能等
# 打断点
我们来看看在浏览器中打断点的一些方式。
(1) 代码断点。
常用的浏览器代码断点,在 Sources 面板 Javascript 文件行号处设置断点,如图我们下了个断点:
这里我们在请求发起的位置打了个断点,每次我们在搜索输入框输入的时候,都会发送请求,触发 debug 模式。
这里除了常规断点外, 还有个条件断点(右键 -> conditional breakpoint), 在设置的条件为true
时才会断电, 在循环中需要断点时比较有用。断点后可以查看堆栈、变量。
(2) 事件断点。
元素上事件断点:某一事件/某类事件,从Elements > Event Listeners
中进行。
(3) DOM 断点。
一般是 DOM 结构改变时触发。有时候我们需要监听某个 DOM 被修改情况,而不关心是哪行代码做的修改(也可能有多处都会对其做修改),可以直接在 DOM 上设置断点。
在元素审查的Elements
标签页中在某个元素上右键菜单里可以设置三种不同情况的断点:
- 子节点修改
- 自身属性修改
- 自身节点被删除
(4) XHR 断点。
右侧调试区有一个XHR Breakpoints
,点击+
并输入 URL 包含的字符串,即可监听该 URL 的 Ajax 请求,输入内容就相当于 URL 的过滤器。
一旦 XHR 调用触发时就会在request.send()
的地方中断。
(5) 全局事件断点。
对事件发生时断点,不会限定在元素上,只要是事件发生,并且有handler
就断点。
还可以对resize
、Ajax
、setTimeout/setInterval
断点。
关于断点调试,除了几种工具和方式的了解以外,更多的需要在实际工作中进行实践才能掌握。用得好的话,谷歌源码也照样能趴出来里面的实现。
# 调试样式
样式的调试需要有个前提,就是对一些样式属性有很好的认识和理解,尤其涉及盒子模型、display
和定位等。样式的规则除了一些基本的逻辑能遵循(可参考前面 1.2.1 章节内容),更多的则是丰富的经验,多写、多练。
在此基础上,一般样式的调试逻辑大概会是这样:
- 样式是否生效
- 文件、相关样式代码是否加载
- 是否被其他样式覆盖(优先级问题)
如上图,一般我们会在选中对应的元素后,从上往下来找到生效(或不生效)的样式,同时也可以定位到对应的源文件。
这里面如果是本地环境调试的话,在 source map 的支持下,我们甚至可以直接在浏览器中修改源文件,保存生效。
# 调试 Javascript 脚本
我们可以通过添加alert()
、console
、debugger
相关代码的方式,进行调试日志输出和断点。
(1) alert。
alert()
会在窗口中显示一个警告对话框,是特别古老的调试方式,以前有些浏览器不支持控制台调试的时候可以这么操作。
由于alert()
会阻塞进程,并且输出内容只支持局限的参数类型,因此现在几乎没什么人会使用了。
(2) console。
可以使用console
来打日志。在生产环境的代码通常是编译后压缩后的代码,浏览器断点调试很不方便,或者是用户的反馈无法进行现场定位,此时通过日志获取需要的信息显得尤为重要。
console
常用的几个方法有:
console.log()
:打印字符串,以及对象、变量什么的都可以console.info()
:打印以感叹号字符开始的信息,使用方法和log
相同console.error()
:打印一条错误信息
养成在代码中通过console
打日志的习惯,在遇到问题的时候能更加高效地定位和解决。
(3) debugger。
当debugger
被调用时, 执行暂停在debugger
语句的位置,就像在脚本源代码中的断点一样。
断点的好处在于,我们可以直接看到代码的执行调用关系,也可以在断点位置查看上下文的变量情况,可以直观地看到问题在哪。
一般 Javascript 的调试逻辑,未按预期执行会有这样的原因:代码未执行到理想的位置。
这时候我们要思考这样的问题:
(1) 为事件触发执行 -> 检测事件是否被触发。
(2) 在函数中执行 -> 检测函数是否被调用。
(3) 在判断语句中执行 -> 检测判断是否正确。
我们可以在这些地方进行输出,或者打下断点:
(1) 事件触发的地方。
(2) 函数调用过程。
(3) 判断语句(if
等)。
以上是类似的推导逻辑,我们在写代码时,会有一个预期的执行顺序和期望,如果说不生效,则我们可以:
- 从前往后执行步骤,看在哪一步分了岔路
- 从后往前打下断点,看在哪一步走丢了
其实最重要的是思路需要清晰,如果说你连自己要做的功能,逻辑还没理清楚的话,编写的代码质量不会高,同时调试性能也会随着下降。
← 1.3.1 编写页面 1.3.3 请求联调 →