寫 Node.js 代碼,從學會調試開始


大家好,我是若川(點這里加我微信?ruochuan12,長期交流學習)。今天推薦這篇調試文章,熟悉我的讀者都知道我寫的源碼文章都多次強調要調試,而且寫了調試方法

點擊下方卡片關注我、加個星標,或者查看源碼等系列文章。學習源碼整體架構系列、年度總結、JS基礎系列


在紛繁復雜的代碼世界中,出錯是難免的,也許在傳統的前端代碼中,你習慣于 console 來排查問題,這是不合理的,在現代的社會下,調試代碼是你最快找到問題的方法。

這篇文章就是教你如何快速的使用調試找到問題。查找和識別錯誤的速度越快,你下班的時間就越早:)。

在當前 Node.js v15 版本下,以前非常多的調試方式已經失效了,Node.js 傳統的調試協議也進行了許多升級,我們按照最新的方式,來告訴你如何調試。

為什么要使用調試

眾所周知,代碼是寫(調)出來的,而不是猜出來的。

如果不通過調試運行代碼,那么意味著需要去猜測代碼中發生的事情,YY 一下,如果代碼運行到這個地方,這個值可能是什么。使用調試的主要好處就是可以觀察程序的運行情況,而不用做假設,可以一次跟隨程序執行一行代碼。

另一方面,你可以控制代碼執行的邏輯,你可以暫定執行,或者逐行運行,甚至修改內存中的值,讓它走到另一個分支里。

Node.js 內置的調試

使用 Node.js 內置的調試方式是最簡單直接的,但是現階段都有 IDE,所以大家都不太關心底層的實現,一鍵開啟調試就行了。

而實際上 IDE 的調試都是基于這個內置調試之上的。

在了解內置的 Node.js 調試方式之前,我們先來了解一下另一個概念:斷點(breakpoint)。

斷點

顧名思義,斷點就是能斷住代碼執行的點,一般情況下,它的表現真的是個點。

比如 vscode 里的斷點(紅紅的點,十分醒目)。

image.png

斷點會強制任何 JavaScript 調試器在給定點暫停。這樣就可以讓代碼執行到這個地方停下,觀察這行代碼以及之后代碼里的變量值。

讓我們回歸傳統,在沒有 IDE 的情況下(比如文本編輯器,Vim 啥的),都是使用 debugger?語句來讓打斷點的。

您使用調試器語句。您可以在代碼的任何位置添加此語句,比如:

async function initMethod() {debugger;console.log('bbb');
}initMethod();

這樣,我們就希望調試的時候會在這一行停下來。

調試模式

光有斷點還不行,普通情況下,Node.js 會忽略這個 debugger,只有開了調試模式才會暫停到這一行(原因是調試器太強大,有些惡意行為可以通過它注入代碼)。

通過給 node 增加 --inspect?參數才會開啟調試模式,這個模式下,還會開放一個默認的 9229 端口,允許其他 IDE 接入。

這個模式下,會輸出下面的信息:

Debugger listening on ws://127.0.0.1:9229/d598ab05-88e8-433f-b641-bf2766da97f5
For help, see: https://nodejs.org/en/docs/inspector

ws://127.0.0.1:9229/d598ab05-88e8-433f-b641-bf2766da97f5?是暴露的調試鏈接,里面包含了協議,host,端口和一個唯一的 uuid。這是一個標準 v8 調試協議。

我們執行一下這個命令。

咦,為啥什么反應都沒有,代碼直接執行結束了,腦中一個大大問號?

事實上,僅僅開啟調試還是不夠的,調試器還沒有接收到足夠的信息,或者說沒有一個展現調試的地方。

node 還提供了另一個會卡住的調試命令。--inspect-brk?會停在代碼的第一行,等待下一步的指示,用他就行了。但是這只是普通的卡住代碼,我們需要能支持 v8調試協議的 UI。

有許多種方法可以作為 UI,而最簡單的就是我們電腦上一般都會有的 Chrome 瀏覽器。

Chrome 自帶了一個調試頁 chrome://inspect/?,打開后,如果是在本機,會直接列出可調式的端口和文件地址(如果在遠程,也可以配置 ip)。

點擊這個 inspect?,添加我們的項目后,藍色的斷點條就乖乖的展現到眼前了。這個時候,我們就可以進行單步調試了(不需要 debugger 了)。

在 Chrome UI 打開的時候,控制臺會輸出一句話。

表明這個調試協議已經連上了 node 開啟的調試端口。

我們總結一下,整個調試分為兩個部分,“開啟 node 調試端口” + “符合 v8調試協議的調試器 attach 到調試端口”。

VSCode 調試

VSCode 是我們最常用的 IDE,集成了調試的 UI,所以我們不再需要開啟 Chrome 來調試了。

本質和最基本的一樣,開啟調試端口,連接調試端口。只是 VSCode 本身是個編輯器,可以直接在其之上打斷點,集成度更高,這也是為什么我們一般都使用 IDE 的緣故。

VSCode 提供了一個調試 UI,需要用戶配置一個 launch.json(等價于啟動命令)。

image.png

內容如下,核心是 runtimeExecutable?使用的命令,以及 runtimeArgs?參數,這里不再需要 --inspect?了(IDE內部會處理)。

{// 使用 IntelliSense 了解相關屬性。// 懸停以查看現有屬性的描述。// 欲了解更多信息,請訪問: https://go.microsoft.com/fwlink/?linkid=830387"version": "0.2.0","configurations": [{"name": "test","type": "node","request": "launch","cwd": "${workspaceRoot}","runtimeExecutable": "node","runtimeArgs": ["test.js"],"console": "integratedTerminal","protocol": "auto","restart": true,"port": 7001,"autoAttachChildProcesses": true}]
}

在上面的配置字段中有個 request?字段,有兩個值可以選擇:launch?和 attach?, 它表示VS Code中核心的兩種調試模式。

launch 指的是直接由編輯器啟動(直接 fork 一個進程),比如我們這個示例,而 attach 表示服務已經啟動,我們是 attach 到原來那個進程中,比如上面的 Chrome 調試。_ 然后打上斷點,執行就行了。

執行的時候,我們發現命令行會發現一段話。

cd /Users/harry/project/application/my_midway_app ; /usr/bin/env 'NODE_OPTIONS=--require "/Applications/Visual Studio Code.app/Contents/Resources/app/extensions/ms-vscode.js-debug/src/bootloader.bundle.js" --inspect-publish-uid=http' 'VSCODE_INSPECTOR_OPTIONS={"inspectorIpc":"/var/folders/xw/yl56_kmj5nd_r0cql7rcv8640000gn/T/node-cdp.94650-2.sock","deferredMode":false,"waitForDebugger":"","execPath":"/Users/harry/.nvs/default/bin/node","onlyEntrypoint":false,"autoAttachMode":"always","fileCallback":"/var/folders/xw/yl56_kmj5nd_r0cql7rcv8640000gn/T/node-debug-callback-02a1ac2abe751152"}' /Users/harry/.nvs/default/bin/node test.js

第一個 cd 忽略,我們主要看看中間這段。VSCode 啟動的時候加載 bootloader.bundle.js 這個文件,然后傳了一堆 IPC 啟動參數,比如創建了一個 sock 文件,其余的把 launch 里的參數翻譯了一下傳入。

核心就是這個 bootlaoder?文件,由于 VSCode 是 ts 寫的,這個文件的源碼在這。

https://github.com/microsoft/vscode-js-debug/blob/ca280351b2/src/targets/node/bootloader.ts

最核心的代碼是 inspectOrQueue?方法,代碼如下,其中有幾個特別關鍵的地方。

function inspectOrQueue(env: IBootloaderInfo): boolean {// 省略// 如果沒有傳 --inspect,則開啟調試端口const openedFromCli = inspector.url() !== undefined;if (!openedFromCli) {// if the debugger isn't explicitly enabled, turn it on based on our inspect modeif (!shouldForceProcessIntoDebugMode(env)) {return false;}inspector.open(0, undefined, false); }const info: IAutoAttachInfo = {ipcAddress: env.inspectorIpc || '',pid: String(process.pid),telemetry,scriptName: process.argv[1],inspectorURL: inspector.url() as string,waitForDebugger: true,ppid: String(env.ppid ?? ''),};if (mode === Mode.Immediate) {// 同步模式,直接跟著應用啟動,監聽調試端口spawnWatchdog(env.execPath || process.execPath, info);} else {// 異步模式,等進程啟動,attach 監聽端口const { status, stderr } = spawnSync(env.execPath || process.execPath,['-e',`const c=require("net").createConnection(process.env.NODE_INSPECTOR_IPC);setTimeout(()=>{console.error("timeout"),process.exit(1)},10000),c.on("error",e=>{console.error(e),process.exit(1)}),c.on("connect",()=>{c.write(process.env.NODE_INSPECTOR_INFO,"utf-8"),c.write(Buffer.from([0])),c.on("data",e=>{console.error("read byte",e[0]),process.exit(e[0])})});`,],{env: {NODE_SKIP_PLATFORM_CHECK: process.env.NODE_SKIP_PLATFORM_CHECK,NODE_INSPECTOR_INFO: JSON.stringify(info),NODE_INSPECTOR_IPC: env.inspectorIpc,},},);}// 省略return true;
}

不管是異步還是同步的模式,其原理都是 Node.js 最基礎的 “開啟端口”,“連接調試端口” 這兩個步驟。VSCode 還會考慮到別的場景,比如代碼創建子進程時,會將子進程也自動添加調試參數,方便自動 attach 等。

在這里,我們會發現一個新的名詞,叫 AutoAttach?。這是 VSCode 在 2018 年 7 月提出的新名詞,微軟表示用戶基本都不太會寫 launch.json 文件,經常寫錯(沒錯,就是我),所以為了簡化寫法,特地做的新功能。

這個功能怎么用呢?

簡單的來說,只要啟動的 node 加上 --inspect?命令,VSCode 就能自動監視到,并且 attach 到進程里開啟調試,不再需要復雜的配置。開啟的命令加到了選項里(cmd+shift+p 搜索)。

有幾種附加方式。比較常用的是僅帶標志。

這樣我們只要在 VSCode 終端里輸入任意帶有 --inspect?的命令,就會自動被斷點到了,很香。

總結一下

調試到這里基本就講完了,所有的調試的原理都是一樣的,藉由 Node.js 原生的打開調試端口的能力,不同的 IDE 才能連接到該端口,進而做出更加強大的能力。

比如 VSCode 不僅僅能做傳統的調試,也能增加配置,在執行調試前后增加鉤子,執行自己的命令,這都是擴展能力的體現。

相信你看完這篇文章,對 Node.js 應用的調試方式有了一定的理解,寫出更好的代碼。


最近組建了一個江西人的前端交流群,如果你也是江西人可以加我微信 ruochuan12 拉你進群。


·················?若川出品?·················

今日話題

2019年9月20日那時關注粉絲突破了1000,2020年佛系了很久,運營了快兩年,還沒到達一萬關注,間接說明了運營公眾號的難度。我的目標是早日突破一萬關注,目前進度9062/10000,如果你愿意幫忙宣傳我的公眾號助力早日突破五位數,那真是太好了。歡迎分享、收藏、點贊、在看我的公眾號文章~

一個愿景是幫助5年內前端人走向前列的公眾號

可加我個人微信 ruochuan12,長期交流學習

推薦閱讀

我在阿里招前端,我該怎么幫你?(現在還能加我進模擬面試群)

若川知乎問答:2年前端經驗,做的項目沒什么技術含量,怎么辦?

點擊方卡片關注我、加個星標,或者查看源碼等系列文章。
學習源碼整體架構系列、年度總結、JS基礎系列

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/275963.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/275963.shtml
英文地址,請注明出處:http://en.pswp.cn/news/275963.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

創建用戶友好的表單

Forms are a common way to engage with users and could be a user’s first impression of your product. Since forms aren’t always the user’s favourite thing, it is essential to make filling out forms as easy as possible. Let’s go over a few tips for creati…

細節決定成敗—關于.net的.dll.refresh文件

一直在做.net的項目,c/s的、b/s的,一直沒有注意這個東西。眾所周知,.net的程序生成后會在bin目錄下生成.dll文件,而.dll.refresh這個文件從何而來呢?那天無聊地google了下才知,這個東東是在你的項目中引用第…

環境在c盤_如何給女朋友解釋為什么 Windows 上面的軟件都把自己安裝在 C 盤

本文經授權轉載自漫畫編程(ID:mhcoding)周末,我在家里面看電視,女朋友正在旁邊鼓搗她的電腦,但是好像并不是很順利,于是就有了以下對話。計算機存儲我們使用的計算機中,保存信息的介質有兩類:一…

能讓你縱享絲滑的SSR技術,轉轉這樣實踐

大家好,我是若川(點這里加我微信 ruochuan12,長期交流學習)。今天推薦這篇圖文并茂的SSR技術文章。這是江西前端群里一個小伙伴的文章。群里小伙伴很多都在知名大廠,但他們都很低調。點擊下方卡片關注我、加個星標&…

魅族魅藍mirror簡單打開usb調試模式的步驟

經常我們使用安卓手機鏈接電腦的時候,或者使用的有些應用比如我們企業營銷團隊經常使用的應用引號精靈,以前使用的老版本就需要開啟USB調試模式下使用,現經常新版本不需要了,如果手機沒有開啟USB調試模式,電腦則無辦法…

hp-ux 單用戶 啟動_UX備忘單:搜索與瀏覽

hp-ux 單用戶 啟動重點 (Top highlight)When designing search results and interest sites, you have to keep in mind what ‘mode’ your user is in. Are they in ‘searching mode’ or ‘browsing mode’? This will help you determine how to design your platform to…

細數開源歷史上的九個重大事件

開放源碼(開源)的精神在于使用者可以使用、復制、散布、研究和改進軟件。這可以追溯到20世紀60年代,至今已有半個世紀了。伯樂在線-職場博客的這篇文章將列舉開源歷史上的九大重要事件。雖然本文不是專門對開源產品,但還是說到了一…

有贊大數據平臺安全建設實踐

一、概述 在大數據平臺建設初期,安全也許并不是被重點關注的一環。大數據平臺的定位主要是服務數據開發人員,提高數據開發效率,提供便捷的開發流程,有效支持數倉建設。大數據平臺的用戶都是公司內部人員。數據本身的安全性已經由公…

請先設置tkk_理光MP2014掃描至文件夾的設置方法

理光旗下的2014系列入門級A3黑白復印機市場保有量較大,該系列機型加裝M16網卡后可以方便的實現掃描至文件夾功能,經常有客戶咨詢該機型的掃描設置方法,下面我就以MP2014D為例來演示一下該機型的SMB掃描設置方法:首先是在電腦上建立…

聽說現在都考這些React面試題

大家好,我是若川。最近刷脈脈看見圈里都在聊面試,吐槽最多的還是萬年考點 React 和 Vue。不過關于兩者的比較似乎有點針尖對麥芒的趕腳。確實,面試的偏重點往往映射公司對該框架的重視程度,但也不能一概而論,去學習或放…

開發中的問題——環境相關

開始了解Android差不多兩周了,作為一名.net開發者,首次接觸Java類的技術,免不了會碰到一些問題,開博的第一篇就來說說自己遇到的問題以及一些感受。關于Android開發環境的搭建,網上已經有很多,其實等更新完…

荒島余生為什么沒有打開包裹_您會帶到荒島什么辦公桌設置?

荒島余生為什么沒有打開包裹Throughout life, you experience a lot of desks and a lot of desk setups. Real or virtual, at the office or at home, temporal or permanent — just a way to call it, nothing is permanent— a big one with a great office view or a sma…

c++ 整數取反_c++ 取反運算符“~”

取反符將二進制表示的數字中的0變為1, 1變為0但是需要注意的是c中對int型進行取反操作時,將前面的前導0也進行了取反(int型變量為32bit)。比如1的二進制表示是00000000 00000000 00000000 00000001~(00000000 00000000 00000000 00000001) 11111111 11111111 11111…

第五課 路由之初識路由

1.路由快速入門 1.1 概念 是指把數據從一個地方傳送到另一個地方的行為和動作,而路由器,正是執行這種行為動作的機器。它的英文名稱為Router,是一種連接多個網絡或者網段的網絡設備,它能將不同網絡或者網段之間的數據信息進行“翻…

Console Snacks[摘自Advanced Rails Recipes]

1. Write Console Methods在~/.irbrc定義ActvieRecord::Base.connection.select_all方法1.# ~/.railsrc2.def sql(query)3.ActiveRecord::Base.connection.select_all(query)4.end1.# ~/.irbrc2.if ENV[RAILS_ENV]3.load File.dirname(__FILE__) /.railsrc4.end這樣就可以在直…

如何使用 React 和 React Hooks 創建一個天氣應用

大家好,我是若川(點這里加我微信 ruochuan12,長期交流學習)。今天推薦一個練手的React項目,創建天氣應用,相信很快能看完。昨天發送書掉粉18人,是我沒想到的,送書一般是出版社按閱讀…

擬態防御_純素食漢堡的擬態

擬態防御If people are so against the idea of pigs and chickens being chopped up why would they want to buy fake bacon with realistic visual streaks of pork fat, or soy meat that tries to replicate the streaky texture of cooked chicken flesh? Surely these …

delphi 算術溢出解決方法_性能優化系列:JVM 內存劃分總結與內存溢出異常詳解分析...

前言那些使用過 C 或者 C 的讀者一定會發現這兩門語言的內存管理機制與 Java 的不同。在使用 C 或者 C 編程時,程序員需要手動的去管理和維護內存,就是說需要手動的清除那些不需要的對象,否則就會出現內存泄漏與內存溢出的問題。如果你使用 J…

微信小程序如何發送 http 請求

2019獨角獸企業重金招聘Python工程師標準>>> 為什么要使用云函數發送 http 請求小程序云函數5 個可信域名不受限制需要備案無需備案在一些特殊情境, 比如域名沒有備案或域名 5 個以上就需要使用云函數發送 HTTP 請求了. 如何使用云函數發送 HTTP 請求? 在云函數中能…

H5 頁面列表緩存方案

大家好,我是若川(點這里加我微信 ruochuan12,長期交流學習)。今天給大家介紹一下關于h5頁面的列表緩存方案。感謝屏幕前的你一直關注著我。點擊下方卡片關注我、加個星標,或者查看源碼等系列文章。學習源碼整體架構系列…