新聞中心
做為前端開(kāi)發(fā),想必大家都寫(xiě)過(guò) Node.js 的代碼,也大概率用 debugger 斷點(diǎn)調(diào)試過(guò)。

浮山網(wǎng)站建設(shè)公司成都創(chuàng)新互聯(lián),浮山網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為浮山上1000+提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)網(wǎng)站制作要多少錢,請(qǐng)找那個(gè)售后服務(wù)好的浮山做網(wǎng)站的公司定做!
我們可以用 Chrome Devtools 調(diào)試 Node.js 代碼,也可以用 VSCode 來(lái)調(diào)試它。調(diào)試工具是 Node.js 開(kāi)發(fā)的基礎(chǔ)工具了。
但現(xiàn)在好用的調(diào)試工具也不是一開(kāi)始就這樣的,它經(jīng)歷了一系列的演變過(guò)程。今天我們就來(lái)聊聊 Node.js 調(diào)試工具背后的故事吧。
相信還是有部分同學(xué)不知道 Node.js 代碼怎么調(diào)試的,所以我們先來(lái)過(guò)一遍怎么調(diào)試 Node.js 代碼:
調(diào)試 Node.js 代碼
準(zhǔn)備一段簡(jiǎn)單的 Node.js 代碼用來(lái)調(diào)試:
const os = require('os');
function func(a, b) {
return a + b;
}
console.log(func(1,2));
console.log(os.cpus());它的邏輯就是執(zhí)行了一個(gè)加法,然后打印了 cpu 的核心的情況。
直接執(zhí)行是這樣的:
打印了 1 + 2 的結(jié)果,也就是 3 ,也打印了 CPU 核心的情況,8 核的 M1 芯片。
那怎么斷點(diǎn)調(diào)試呢?
執(zhí)行的時(shí)候加上一個(gè) --inspect 的參數(shù),就會(huì)啟動(dòng)調(diào)試服務(wù)了:
指定 --inspect-brk 參數(shù)還會(huì)在首行斷住。
可以看到啟動(dòng)了一個(gè) WebSocket 的服務(wù)端,這就是調(diào)試服務(wù),用某個(gè)調(diào)試工具客戶端連上就行了:
調(diào)試客戶端可以是 Chrome Devtools 也可以是 VSCode。
Chrome Devtools
比如用 Chrome Devtools 來(lái)連上是這樣的:
打開(kāi) chrome://inspect 的 url 就會(huì)看到這個(gè)可以連接的 target:
點(diǎn)擊 inspect 就是連上這個(gè) ws 服務(wù)端來(lái)做調(diào)試:
右邊可以看到調(diào)用棧、上下文的變量,可以單步執(zhí)行、可以打斷點(diǎn)等。
打印信息會(huì)輸出在 console:
VSCode
用 VSCode 調(diào)試的話需要在項(xiàng)目根目錄下加一個(gè) .vscode/launch.json 的文件,類型選擇 attach to process:
很容易理解,就是連接到目標(biāo)進(jìn)程的 ws 服務(wù)的意思:
端口是 9229,也就是我們調(diào)試服務(wù)啟動(dòng)的端口。
然后點(diǎn)擊調(diào)試面板的調(diào)試按鈕來(lái)啟動(dòng):
這樣也會(huì)在斷點(diǎn)處斷住,可以單步運(yùn)行、可以看調(diào)用棧、上下文的信息:
看到這里不知道有沒(méi)有同學(xué)會(huì)覺(jué)得這樣太麻煩了,每次都要起一個(gè) ws 調(diào)試服務(wù),然后再 attach,不能把這兩步合并到一塊自動(dòng)給做了嗎?
沒(méi)錯(cuò),確實(shí)可以合并到一塊,也就是起一個(gè) ws 服務(wù),然后自動(dòng) attach 上:
調(diào)試配置選擇 launch program:
只需要指定要調(diào)試的 Node.js 模塊的地址,然后點(diǎn)擊啟動(dòng),這樣就可以調(diào)試了:
注意,想達(dá)到和 --inspect-brk 一樣的首行斷住的效果,這里要執(zhí)行 stopOnEntry 為 true。
效果是一樣的:
這樣比直接啟動(dòng) ws 調(diào)試服務(wù),然后再 attach 還少了一步。
怎么調(diào)試 Node.js 講完了,大家是不是覺(jué)得這樣調(diào)試還是蠻方便的呢?
但其實(shí)最開(kāi)始的調(diào)試并沒(méi)有這么好用,接下來(lái)我們看下之前的調(diào)試都是咋樣的吧:
Node.js Debugger 的歷史
從前面的實(shí)踐中我們也能發(fā)現(xiàn),調(diào)試的原理還是蠻清晰的:
啟動(dòng)一個(gè) WebSocket 服務(wù)端來(lái)提供各種運(yùn)行時(shí)的信息,這個(gè)服務(wù)是 JS Runtime 提供的,也就是 Node。
啟動(dòng)一個(gè) WebSocket 客戶端來(lái)實(shí)現(xiàn)調(diào)試的 UI,包括調(diào)用棧、上下文的顯示、打斷點(diǎn)、單步運(yùn)行等功能,比如我們用過(guò)的 Chrome Devtools、VSCode Debugger。
中間傳輸?shù)南⒕褪钦{(diào)試協(xié)議:
我們知道 Node.js 是基于 V8 的,V8 本身有調(diào)試協(xié)議 V8 Debug Protocol,所以 Node.js 最早的調(diào)試協(xié)議也就是 V8 Debug Protocol。
當(dāng)時(shí)調(diào)試是這樣的:
通過(guò) node debug 來(lái)跑 js 文件,會(huì)在首行斷?。?/p>
然后可以通過(guò) run、cont、next、step 等命令來(lái)實(shí)現(xiàn)單步調(diào)試,通過(guò) backtrace 打印調(diào)用棧,通過(guò) setBreakPoint 等設(shè)置斷點(diǎn):
比如用 setBreakPoint(sb)命令在第四行打個(gè)斷點(diǎn):
然后 cont(c) 命令繼續(xù)執(zhí)行,backtrace(bt) 打印調(diào)用棧:
雖然該有的調(diào)試功能都有,但是這樣調(diào)試還是比較費(fèi)勁的。
怎么能不用命令行調(diào)試,而是用 UI 來(lái)調(diào)試呢?
當(dāng)時(shí) Node 就瞄準(zhǔn)了 Chrome Devtools,它的調(diào)試 UI 就很不錯(cuò)。
但是 Chrome Devtools 的調(diào)試協(xié)議是 Chrome Devtools Protocol,和 V8 Debug Protocol 還是有些差距的,怎么能用上 Chrome Devtools 的調(diào)試工具來(lái)調(diào)試 Node 呢?
其實(shí)還挺容易想到的,就是加一個(gè)中間的服務(wù)來(lái)做轉(zhuǎn)換:
這個(gè)服務(wù)是 node-inspector 這個(gè)包提供的。
所以當(dāng)時(shí) node debug 服務(wù)跑起來(lái)之后,還要要再跑一個(gè) node-inspector 服務(wù),這樣才能用 chrome devtools 來(lái)調(diào)試 Node.js 代碼。
后來(lái)維護(hù) Node.js 的那些人覺(jué)得這樣也太麻煩了,要不讓 Node.js 提供的調(diào)試協(xié)議就直接就是兼容 Chrome Devtools Protocol 的吧。
當(dāng)時(shí)就有了這樣一個(gè) pr,把 v8 inspector 集成到 Node.js 中:
這個(gè) v8 inspector 就是從 chrome 的內(nèi)核 blink 里剝離出來(lái)的讓 v8 支持 chrome devtools protocol 的部分。
很明顯這需要 v8 團(tuán)隊(duì)的配合,所以說(shuō) Node.js 的發(fā)展還是很依賴 v8 團(tuán)隊(duì)的支持的。
之后 Node.js 就在 v6.3 中加入了這個(gè)功能:
并且在成熟之后去掉了對(duì) v8 debug protocol 的支持,也就是廢棄了 node debug 命令,改為了 node inspect。
啟動(dòng) ws 服務(wù)的方式就是 node --inspect 或者 node --inspect-brk。
當(dāng)然,之前作為兩個(gè)協(xié)議的中轉(zhuǎn)的服務(wù) node-inspector 也就退出了歷史舞臺(tái)。
所以今天,我們可以輕易的用 Chrome Devtools 來(lái)調(diào)試 Node.js 代碼,就如本文開(kāi)始展示的那樣。
當(dāng)然,這里只是說(shuō) Chrome Devtools 調(diào)試 Node.js,在 VSCode 里調(diào)試 Node.js 的話還有另一段小故事:
調(diào)試的原理我們已經(jīng)知道了,就是 ws 客戶端和服務(wù)器的通信,然后基于調(diào)試協(xié)議來(lái)完成不同的功能。Node.js 是這樣,其他語(yǔ)言也是這樣。
VSCode 是一個(gè)通用的編輯器,是要支持多種語(yǔ)言的,也就是它的調(diào)試 UI 要支持多種調(diào)試協(xié)議。
要同一個(gè)調(diào)試工具同時(shí)支持不同的協(xié)議有點(diǎn)不太現(xiàn)實(shí),那怎么辦呢?
可以加一個(gè)中間層,VSCode 的調(diào)試 UI 只要支持這個(gè)中間的調(diào)試協(xié)議就可以了,其余的調(diào)試協(xié)議適配到這個(gè)調(diào)試協(xié)議上來(lái):
這就是 DAP 協(xié)議,debugger adpater protocol。
Node.js 在把調(diào)試工具的協(xié)議換成兼容 Chrome Devtools Protocol 的協(xié)議之后,只要實(shí)現(xiàn)個(gè) DAP 的 adapter 就可以對(duì)接到 VSCode 的調(diào)試工具了。
這樣我們就可以在 VSCode 里調(diào)試 Node.js 了。
Node.js 調(diào)試的故事講完了,我們來(lái)總結(jié)下:
總結(jié)
現(xiàn)在 Node.js 的調(diào)試可以用 Chrome Devtools 也可以用 VSCode,都是挺方便的。
但是它不是一開(kāi)始就這么好用的,我們聊了下它之前的故事:
調(diào)試的原理就是 Node 啟動(dòng) ws 的調(diào)試服務(wù),調(diào)試客戶端(chrome devtools、vscode 等)對(duì)接這個(gè)調(diào)試服務(wù)并實(shí)現(xiàn)交互的 UI,基于傳輸?shù)恼{(diào)試協(xié)議來(lái)完成調(diào)試。
最開(kāi)始 Node.js 的調(diào)試協(xié)議是 v8 debug protocol,只能用命令行調(diào)試。
為了直接用 Chrome Devtools 的 UI 來(lái)調(diào)試,就實(shí)現(xiàn)了 node-inspector 的中轉(zhuǎn)服務(wù)來(lái)實(shí)現(xiàn) v8 debug protocol 到 chrome devtools protocol 的協(xié)議轉(zhuǎn)換。
這樣還是太麻煩了,所以后來(lái) Node.js 和 v8 團(tuán)隊(duì)合作實(shí)現(xiàn)了 v8-inspector,可以讓 Node.js 提供的調(diào)試協(xié)議是直接兼容 Chrome Devtools Protocol 的。
這樣我們就可以直接用 node --inspect 起 ws 調(diào)試服務(wù),然后用 Chrome Devtools 連接調(diào)試了。
VSCode 為了同一個(gè)調(diào)試 UI 支持不同語(yǔ)言的調(diào)試,設(shè)計(jì)了中間的調(diào)試協(xié)議 Debug Apapter Protocol。Node.js 想在 VSCode 里調(diào)試的話只要實(shí)現(xiàn)對(duì)應(yīng)的 adapter 即可。
今天我們用 Chrome Devtools 或者 VSCode Debugger 都可以輕松調(diào)試 Node.js 代碼,其實(shí)這背后還是有一段挺有意思的故事的。
當(dāng)前文章:Node.js調(diào)試一路走來(lái)經(jīng)歷了什么
當(dāng)前網(wǎng)址:http://m.5511xx.com/article/dhpeeig.html


咨詢
建站咨詢
