放棄 console-log 吧!用 Debugger 你能讀懂各種源碼

很多同學不知道爲什麼要用 debugger 來調試,console.log 不行麼?

還有,會用 debugger 了,還是有很多代碼看不懂,如何調試複雜源碼呢?

這篇文章就來講一下爲什麼要用這些調試工具:

console.log vs Debugger

相信絕大多數同學使用 console.log 調試的,把想看的變量值打印在控制檯。

這樣能滿足需求,但是遇到對象的打印就不行了。

比如我想看 webpack 源碼裏的 compilation 對象的值,我打印了一下:

但你會發現對象的值也是對象的時候不會展開,而是打印一個 [Object] [Array] 這種字符串。

更致命的是打印的太長會超過緩衝區的大小,terminal 裏會顯示不全:

而你用 debugger 來跑,在這裏打個斷點來看就沒這些問題了:

有的同學可能會說,那打印一個簡單的值的時候用 console.log 還是很方便呀。

比如這樣:

真的麼?

那還不如用 logpoint:

代碼執行到這裏就會打印:

而且沒有污染代碼,用 console.log 的話調試完之後這個 console 不也得刪掉麼?

但是 logpoint 不用,它就是個斷點的設置,不在代碼裏。

當然,最重要的是 Debugger 調試是可以看到調用棧和作用域的!

首先是調用棧,它就是代碼的執行路線。

比如這個 App 的函數組件,你可以看到渲染這個函數組件會經歷 workLoop、beginWork、renderWithHooks 這些流程:

你可以點開調用棧的每一幀看下都執行了啥邏輯,用到啥數據。比如可以看到這個函數組件的 fiber 節點:

再就是作用域,點擊每一個棧幀就可以看到每個函數的作用域中的變量:

用 Debugger 可以看到代碼的執行路徑,每一步的作用域信息。而你用 console.log 呢?

只能看到那個變量值而已。

拿到的信息量的差距不是一點半點,調試時間長了,別人會對代碼的運行流程越來越清晰,而你用 console.log 呢?還是老樣子,因爲你看不到代碼執行路徑。

所以,不管是調試庫的源碼還是業務代碼,不管是調試 Node.js 還是網頁,都推薦用 Debugger 打斷點,別再用 console.log 了,就算想打印日誌,也可以用 LogPoint。

而且在排查問題的時候,用 Debugger 的話可以加一個異常斷點,代碼跑到拋異常的地方就會斷住:

可以看到調用棧來理清出錯前都走了哪些代碼,可以通過作用域來看到每一個變量的值。

有了這些東西,排查錯誤不就很輕鬆了麼!

而你用 console.log 呢?

啥也沒,只能自己猜。

Performance

前面說 Debugger 調試可以看到一條代碼的執行路徑,但是代碼的執行路徑往往比較曲折。

比如那個 React 會對每個 fiber 節點做處理,每個節點都會調用 beginWork。處理完之後又會處理下一個節點,再次調用 beginWork:

就像你走了一條小路,然後回到大路之後又走了另一條小路,用 Debugger 只能看到當前這條小路的執行路徑,看不到其他小路的路徑:

這時候就可以結合 Performance 工具了,用 Performance 工具看到代碼執行的全貌,然後用 Debugger 來深入每一條代碼執行路徑的細節。

SourceMap

sourcemap 很重要,因爲我們執行過的都是編譯打包後的代碼,基本是不可讀的,調試這種代碼也沒啥意義,而 sourcemap 就可以讓我們直接調試最初的源碼。

比如 vue,關聯了 sourcemap 之後,我們能直接調試 ts 源碼:

nest.js 也是:

不用 sourcemap 的話,想搞懂源碼,但你調試的是編譯後的代碼,怎麼讀懂呢?

讀懂一行

前面說的 Debugger、Performance、SourceMap 只是調試代碼的工具,那會了調試工具,依然讀不懂代碼怎麼辦呢?

我覺得這是不可能的。

爲什麼這麼說呢?

就拿 react 源碼來說:

switch case 能讀懂吧。三目運算符能讀懂吧。函數調用能讀懂吧。

每一行代碼都能讀懂,而全部的代碼不就是由這一行行代碼組成的麼?

加上我們可以單步執行來知道代碼執行路徑。

爲啥每行代碼都能讀懂,連起來就讀不懂了呢?

那應該是代碼太多了,而你花的時間不夠而已。

先要讀懂一行,一個函數,讀懂一個小功能的實現流程,慢慢積累,之後瞭解的越來越多之後,你能讀懂的代碼就會越多。

總結

這篇文章講了下爲什麼要用調試工具,如何讀懂複雜代碼。

console.log 的弊端太多了,大對象打印不全,會超過 terminal 緩衝區,對象屬性不能展開等等,不建議大家用。就算要打印也可以用 LogPoint。

用 Debugger 可以看到調用棧,也就是代碼的執行路徑,每個棧幀的作用域,可以知道代碼從開始運行到現在都經歷了什麼,而不只是某個變量的值。

此外,報錯的時候也可以通過異常斷點來梳理代碼執行路徑排查報錯原因。

但 Debugger 只能看到一條執行路徑,可以用 Performance 錄製代碼執行的全流程,然後再結合 Debugger 來深入其中一條路徑的執行細節。

此外,只有調試最初的源碼纔有意義,不然調試編譯後的代碼會少很多信息。可以通過 SourceMap 來關聯到源碼,不管是 Vue、React 的源碼還是 Nest.js、Babel 等的源碼。

會了調試之後,就能調試各種代碼了,不存在看不懂的源碼,因爲每一行代碼都是基礎的語法,都是能看懂的,如果看不懂,只可能是代碼太多了,你需要更多的耐心去讀一行行代碼、一個個函數、理清一個個功能的實現,慢慢積累就好了。

掌握基於 Debugger、Performance、SourceMap 等調試代碼之後,各種網頁和 Node.js 代碼都能調試,各種源碼都能讀懂!

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/KyqxU_9t6HpntWeERNvwaA