许多同学不知道为什么要用 debugger 来调试,console.log 不行么?

还有,会用 debugger 了,仍是有许多代码看不明白,如何调试杂乱源码呢?

这篇文章就来讲一下为什么要用这些调试东西:

console.log vs Debugger

相信绝大多数同学运用 console.log 调试的,把想看的变量值打印在控制台。

这样能满意需求,可是遇到目标的打印就不行了。

比方我想看 webpack 源码里的 compilation 目标的值,我打印了一下:

抛弃 console.log 吧!用 Debugger 你能读懂各种源码

但你会发现目标的值也是目标的时分不会打开,而是打印一个 [Object] [Array] 这种字符串。

更丧命的是打印的太长会超过缓冲区的巨细,terminal 里会显示不全:

抛弃 console.log 吧!用 Debugger 你能读懂各种源码

而你用 debugger 来跑,在这里打个断点来看就没这些问题了:

有的同学或许会说,那打印一个简略的值的时分用 console.log 仍是很方便呀。

比方这样:

抛弃 console.log 吧!用 Debugger 你能读懂各种源码

真的么?

那还不如用 logpoint:

抛弃 console.log 吧!用 Debugger 你能读懂各种源码

抛弃 console.log 吧!用 Debugger 你能读懂各种源码

代码履行到这里就会打印:

并且没有污染代码,用 console.log 的话调试完之后这个 console 不也得删掉么?

可是 logpoint 不用,它就是个断点的设置,不在代码里。

当然,最重要的是 Debugger 调试是能够看到调用栈和效果域的!

首先是调用栈,它就是代码的履行路线。

比方这个 App 的函数组件,你能够看到烘托这个函数组件会阅历 workLoop、beginWork、renderWithHooks 这些流程:

抛弃 console.log 吧!用 Debugger 你能读懂各种源码

你能够点开调用栈的每一帧看下都履行了啥逻辑,用到啥数据。比方能够看到这个函数组件的 fiber 节点:

再就是效果域,点击每一个栈帧就能够看到每个函数的效果域中的变量:

用 Debugger 能够看到代码的履行途径,每一步的效果域信息。而你用 console.log 呢?

只能看到那个变量值而已。

拿到的信息量的距离不是一点半点,调试时刻长了,别人会对代码的运行流程越来越明晰,而你用 console.log 呢?仍是老样子,由于你看不到代码履行途径。

所以,不管是调试库的源码仍是业务代码,不管是调试 Node.js 仍是网页,都推荐用 Debugger 打断点,别再用 console.log 了,就算想打印日志,也能够用 LogPoint。

并且在排查问题的时分,用 Debugger 的话能够加一个反常断点,代码跑到抛反常的地方就会断住:

抛弃 console.log 吧!用 Debugger 你能读懂各种源码

抛弃 console.log 吧!用 Debugger 你能读懂各种源码

能够看到调用栈来理清出错前都走了哪些代码,能够经过效果域来看到每一个变量的值。

有了这些东西,排查错误不就很轻松了么!

而你用 console.log 呢?

啥也没,只能自己猜。

Performance

前面说 Debugger 调试能够看到一条代码的履行途径,可是代码的履行途径往往比较弯曲。

比方那个 React 会对每个 fiber 节点做处理,每个节点都会调用 beginWork。处理完之后又会处理下一个节点,再次调用 beginWork:

抛弃 console.log 吧!用 Debugger 你能读懂各种源码

就像你走了一条小路,然后回到大道之后又走了另一条小路,用 Debugger 只能看到当时这条小路的履行途径,看不到其他小路的途径:

抛弃 console.log 吧!用 Debugger 你能读懂各种源码

这时分就能够结合 Performance 东西了,用 Performance 东西看到代码履行的全貌,然后用 Debugger 来深入每一条代码履行途径的细节。

抛弃 console.log 吧!用 Debugger 你能读懂各种源码

SourceMap

sourcemap 很重要,由于咱们履行过的都是编译打包后的代码,基本是不可读的,调试这种代码也没啥意义,而 sourcemap 就能够让咱们直接调试最初的源码。

抛弃 console.log 吧!用 Debugger 你能读懂各种源码

比方 vue,相关了 sourcemap 之后,咱们能直接调试 ts 源码:

抛弃 console.log 吧!用 Debugger 你能读懂各种源码

nest.js 也是:

不用 sourcemap 的话,想搞懂源码,但你调试的是编译后的代码,怎样读懂呢?

读懂一行

前面说的 Debugger、Performance、SourceMap 只是调试代码的东西,那会了调试东西,依然读不明白代码怎样办呢?

我觉得这是不或许的。

为什么这么说呢?

就拿 react 源码来说:

抛弃 console.log 吧!用 Debugger 你能读懂各种源码

switch case 能读懂吧。三目运算符能读懂吧。函数调用能读懂吧。

每一行代码都能读懂,而悉数的代码不就是由这一行行代码组成的么?

加上咱们能够单步履行来知道代码履行途径。

为啥每行代码都能读懂,连起来就读不明白了呢?

那应该是代码太多了,而你花的时刻不够而已。

先要读懂一行,一个函数,读懂一个小功用的完成流程,慢慢堆集,之后了解的越来越多之后,你能读懂的代码就会越多。

总结

这篇文章讲了为什么要用调试东西,如何读懂杂乱代码。

console.log 的弊端太多了,大目标打印不全,会超过 terminal 缓冲区,目标特点不能打开等等,不主张大家用。就算要打印也能够用 LogPoint。

用 Debugger 能够看到调用栈,也就是代码的履行途径,每个栈帧的效果域,能够知道代码从开始运行到现在都阅历了什么,而 console.log 只能知道某个变量的值。

此外,报错的时分也能够经过反常断点来整理代码履行途径来排查报错原因。

但 Debugger 只能看到一条履行途径,能够用 Performance 录制代码履行的全流程,然后再结合 Debugger 来深入其间一条途径的履行细节。

此外,只有调试最初的源码才有意义,不然调试编译后的代码会少许多信息。能够经过 SourceMap 来相关到源码,不管是 Vue、React 的源码仍是 Nest.js、Babel 等的源码。

会了调试之后,就能调试各种代码了,不存在看不明白的源码,由于每一行代码都是基础的语法,都是能看懂的,假如看不明白,只或许是代码太多了,你需要更多的耐心去读一行行代码、一个个函数、理清一个个功用的完成,慢慢堆集就好了。

掌握根据 Debugger、Performance、SourceMap 等调试代码之后,各种网页和 Node.js 代码都能调试,各种源码都能读懂!

(摘自我的小册 《前端调试通关秘籍》)