讓你 nodejs 水平暴增的 debugger 技巧

學習 nodejs 最重要的是什麼?可能每一個人都有本身的答案。javascript

我以爲學習 nodejs 除了要掌握基礎的 api、經常使用的一些包外,最重要的能力是學會使用 debugger。由於當流程複雜的時候,斷點調試可以幫你更好的理清邏輯,有 bug 的時候也能更快的定位問題。java

狼叔說過,是否會使用 debugger 是區分一個程序員 nodejs 水平的重要標誌。node

本文分享一下 debugger 的原理和 vscode debugger 的使用技巧。程序員

debugger 原理

運行 nodejs 代碼的時候,若是帶上了 --inspect(能夠打斷點) 或者 --inspect-brk(能夠打斷點,並在首行斷住) 的參數,那麼就會以 debugger 的模式啓動:web

能夠看到,node 啓動了一個 web socket 的 server,地址是:ws://127.0.0.1:9229/78637688-e8e0-4582-80cc-47655f4bff66chrome

爲何 debugger 要啓動一個 websocket server 呢?express

debugger 的含義就是要在某個地方斷住,能夠單步運行、查看環境中的變量。那麼怎麼設置斷點、怎麼把當前上下文的變量暴露出去呢,就是經過啓動一個 websocket server,這時候只要啓動一個 websocket client 鏈接上這個 server 就能夠調試 nodejs 代碼了。json

v8 debug protocol

連上以後呢,debugger server 和 debugger client 怎麼交流?這就涉及到了 v8 debug protocol。api

經過兩邊都能識別的格式來交流,好比:websocket

在 test.js 的 100 行 設置斷點:

{
    "seq":118,
    "type":"request",
    "command":"setbreakpoint",
    "arguments":{
        "type":"script",
        "target":"test.js",
        "line":100
    }
}
複製代碼

而後查看當前做用域的變量:

{
    "seq":117,
    "type":"request",
    "command":"scope"
}
複製代碼

執行一個表達式:

{
    "seq":118,
    "type":"request",
    "command":"evaluate",
    "arguments":{
        "expression":"a()"
    }
}
複製代碼

以後繼續運行:

{
    "seq":117,
    "type":"request",
    "command":"continue"
}
複製代碼

經過這種方式,client 就能夠告訴 debugger server 如何執行代碼。

debugger client

debugger client 通常都是有 ui 的(固然,在命令行裏面經過命令來調試也能夠,但通常不這麼作)。常見的 js 的 debugger client 有 chrome devtools 和 vscode debugger 等。

咱們寫一個簡單的 js 腳本,經過 node --inspect-brk 跑起來:

能夠看到它啓動在了 9229 端口,

而後,咱們分別經過兩種 client 連上它。

chrome devtools

在 chrome 地址欄輸入 chrome://inspect,而後點擊 configure 來配置目標端口:

把剛纔的端口 9229 填上去:

而後就能夠看到 chrome 掃描到了這個 target,點擊 inspect 就能夠連上這個 debugger server。

以後就能夠設置斷點、單步執行、執行表達式、查看做用域變量等,這些功能都是經過 v8 debug protocol 來實現的。

vscode debugger

在 vscode 裏面寫代碼,在 chrome devtools 裏調試比較麻煩,vscode 也實現了 debugger 的支持,能夠直接用 vscode 來調試。

使用vscode 調試能力的方式是修改項目根目錄下的 .vscode/launch.json 配置。

attach

點擊右下角的按鈕來添加一個配置項。這裏選擇 nodejs 的 attach:

由於已經經過 node --inspect-brk 啓動了 websocket 的 debugger server,那麼只須要啓動 websocket client,而後 attach 上 9229 端口就行。

點擊左側的按鈕,就能夠連上 debugger server 開始調試:

launch

這樣先經過 node --inspect-brk 啓動 debugger server,而後再添加 vscode debug 配置來鏈接上太麻煩了,能不能把這兩步合併呢?

固然能夠,只要添加一個 launch 的配置:

這裏的 type 是 launch,就是啓動 debgger server 而且啓動一個 debugger client 鏈接上該 server。運行的程序是根目錄下的 index2.js,還能夠設置 stopOnEntry 來在首行斷住。

點擊調試,就能夠看到可以成功的調試該 js 文件。

vscode 會啓動 debugger server,而後啓動 debugger client 自動鏈接上該 server,這些都不須要咱們去關心。

這樣咱們就能夠成功的使用 vscode debugger 來調試 nodejs 代碼。

vscode debugger 進階

debugger client 中咱們最經常使用的仍是 vscode,這裏着重講一下 vscode debugger 的各類場景下的配置。

sourcemap

若是調試 ts 代碼,確定不能調試編譯後的代碼,要可以映射回源碼,這個是 sourcemap 作的事情。調試工具都支持 sourcemap,好比 chrome devtools 和 vscode debugger,都支持文件末尾的 sourcemap url 的解析:

//# sourceMappingURL=index.js.map
複製代碼

這樣當調試 index.js的時候,若是它是 ts 編譯的出來的,就會自動找到對應的 ts。

固然,若是調試配置裏面直接指定了 ts,那麼要可以調試須要再配置 outFiles,告訴 vscode 去哪裏找 sourcemap。

image.png

這樣,在 ts 源碼中打的斷點和在編譯出的 js 打的斷點都能生效。

多進程調試

當代碼中有子進程的時候,就有了第二條控制流,須要再啓動一個 debugger。

好比 vscode,它是基於 electron,須要啓動一個主進程,一些渲染進程。主進程是經過 launch 啓動的,而渲染進程則是後來 attach 的。

主進程啓動的時候,經過 --remote-debugging-port 來指定子進程自動的時候的 debugger server 的端口。

outFiles 來指定 sourcemap 的位置,這樣才能夠直接調試 ts 源碼。runtimeExecutable 是用 vscode 的運行時替代掉了 nodejs(通常不須要設置)。

而後渲染進程是後面啓動的,咱們經過參數配置了會啓動在 9222 端口,那麼只要 attach 到那個端口就能夠調試該進程了。

vscode 支持多 target 調試,也就是能夠在 vscode 裏面同時啓動 多個 debugger。能夠切換不一樣的 debugger 來調試不一樣的進程。

彩蛋

debugger 只能打斷點麼,不是的,它還能夠這麼用,加日誌,不污染源碼。

總結

debugger 的使用是一項很重要的能力,對於 nodejs 水平的提高頗有幫助。

nodejs debugger 的原理是 js 引擎會啓動 debugger server(websocket),等待客戶端鏈接,咱們能夠經過各類 debugger client 連上來進行調試,好比 chrome devtools、vscode debugger。

調試 nodejs 代碼更多仍是使用 vscode debugger(固然有的時候也會使用 chrome devtools 調試,基於 chrome devtools 的 memory 來進行內存分析,定位內存泄漏問題的時候頗有幫助)。

vscode debugger 的使用主要是在 .vscode/launch.json 裏面添加調試配置。

調試配置分爲 launch 和 attach 兩種:

  • launch 會啓動 debugger server 並用 debugger client 鏈接上
  • attach 只是啓動 debugger client 鏈接上已有的 debugger server,因此要指定端口

具體的配置項經常使用的有:

  • outFiles 指定 sourcemap 的位置,用來調試 ts 源碼等須要編譯的代碼
  • stopOnEntry 在首行停住
  • args 來指定一些命令行參數
  • runtimeExecutable 當運行時不是 nodejs 的時候須要指定,好比 vscode 或者其餘的一些運行時

基於這些配置咱們就能夠調試各類場景下的 nodejs 代碼,須要編譯的,或者多個進程的。

不誇張地說,若是你熟悉了 debugger 的使用,理解各類 nodejs 代碼都會簡單不少。 但願這篇文章可以幫助你們瞭解 debugger 的原理,而且可以使用 chrome devtools 或者 vscode debugger 來調試 nodejs 代碼。知道有 sourcemap 以及多進程的狀況下都怎麼調試。

相關文章
相關標籤/搜索