網頁會載入資源、執行 JS、渲染介面、儲存資料等,我們開發時怎麼看到執行的狀態呢? 用除錯工具 chrome devtools。它支援 dom 除錯、JS debugger、本地儲存的展示、執行時間的 profile 等。

Node。js 也是同樣,不過它只支援 JS debugger 和 profile。我們可以透過 chrome devtools 或者 vscode debugger 等來除錯。

這些工具都是遠端 attach 到執行的程式上來除錯的,之間怎麼互動資料呢? 透過 webSocket。而且還制定了 chrome devtools protocol 的協議,規定了有什麼能力,如何通訊。

這種基於 websocket 的除錯協議叫做

chrome devtools protocol

。 因為功能比較多,所以分了多個域(一般複雜的東西都會分域),包括 DOM、Debugger、Network、Page 等等,分別放不同的除錯協議。chrome devtools 就是透過這個協議實現的除錯。

新版 chrome(金絲雀版)可以開啟設定中的實驗特性的 Protocol Monitor 面板。

面試官,我實現了一個 Chrome Devtools

就可以看到傳輸的 CDP 資料:

面試官,我實現了一個 Chrome Devtools

這就是 chrome devtools 的原理。

理解了這個原理有什麼用呢?

我們可以重新實現服務端,只要對接了除錯協議,那麼就能夠用 chrome devtools 來除錯。

比如 kraken(把 css 渲染到 flutter)是怎麼做到用 chrome devtools 除錯 dom 和樣式的?就是對接了這個協議。

我們可以重新實現客戶端,只要對接了這個協議,那就可以用任何工具除錯網頁/Node。js。

大家用 chrome devtools 可以除錯 Node。js 和網頁,用 vscode debugger 也可以,用 webstorm debugger 也可以。為什麼呢?因為它們都對接了這個協議。

那我們是不是可以對接這個協議實現一個類似 chrome devtools 的除錯工具呢?

我們來實驗下:

我們啟動 chrome,透過 ——remote-debugging-port 指定除錯埠:

/Applications/Google\ Chrome\ Canary。app/Contents/MacOS/Google\ Chrome\ Canary ——remote-debugging-port=9222

然後連上它。

這裡我們不用直接對接協議,chrome 提供了各種語言的 sdk,呼叫 api 就行:

面試官,我實現了一個 Chrome Devtools

我們先連線上 chrome:

const

CDP

=

require

‘chrome-remote-interface’

);

async

function

test

()

{

let

client

try

{

client

=

await

CDP

();

const

{

Page

DOM

Debugger

}

=

client

//。。。

}

catch

err

{

console

error

err

);

}

}

test

();

然後開啟

http://

baidu。com

,等 2s,做個截圖:

const

CDP

=

require

‘chrome-remote-interface’

);

const

fs

=

require

‘fs’

);

async

function

test

()

{

let

client

try

{

client

=

await

CDP

();

const

{

Page

DOM

Debugger

}

=

client

await

Page

enable

();

await

Page

navigate

({

url

‘https://baidu。com’

});

await

new

Promise

resolve

=>

setTimeout

resolve

2000

));

const

res

=

await

Page

captureScreenshot

();

fs

writeFileSync

‘。/screenshot。jpg’

res

data

{

encoding

‘base64’

});

}

catch

err

{

console

error

err

);

}

}

test

();

檢視下效果:

面試官,我實現了一個 Chrome Devtools

這樣,我們就跑通了 CDP 的第一段程式碼。

其餘的功能,包括 Network、Debugger、DOM 等等也能實現,我們簡單試一下:

await

DOM

enable

();

const

{

root

}

=

await

DOM

getDocument

({

depth

-

1

});

depth 為深度,設定為 -1 就是返回整個 dom:

面試官,我實現了一個 Chrome Devtools

有了這些資料我們是不是可以做 DOM 的瀏覽呢?

還有 DOM。setAttributeValue 可以設定屬性、DOM。getBoxModel 拿到盒模型大小等。

基於這些,我們做個 dom 編輯器沒問題吧。

還有網路部分:

await

Network

enable

();

Network

on

‘responseReceived’

async

evt

=>

{

const

res

=

await

Network

getResponseBody

({

requestId

evt

requestId

});

console

log

evt

response

url

);

console

log

res

body

);

});

我們透過 responseReceived 事件監聽每一個響應,然後再透過 Network。getResponseBody 拿到響應的內容:

面試官,我實現了一個 Chrome Devtools

面試官,我實現了一個 Chrome Devtools

基於這些,我們實現 Network 面板的功能沒問題吧。

還可以對接 profiler:

await Profiler。start();

await new Promise(resolve => setTimeout(resolve,2000));

const { profile } = await Profiler。stop();

面試官,我實現了一個 Chrome Devtools

有這些資料,我們就可以透過 canvas 畫出個火焰圖出來。

理論上來說,chrome devtools 的所有功能我們都能實現。而且,一個網頁同時用多個除錯工具除錯是可以的,因為 websocket 本來就可以有多個客戶端。

面試官,我實現了一個 Chrome Devtools

可能你會說自己實現 chrome devtools 有什麼意義?

大家自己做開源前端專案的時候,一般都是寫個網易雲音樂客戶端,因為有現成的資料可以用。那為什麼不做個 chrome devtools 呢?也有現成的資料啊,啟動瀏覽器就行,而且這個逼格多高啊。

我們也不用實現完整的 chrome devtools,可以單把網路部分、單把 DOM 部分、單把 debugger 部分實現了,可以做不同的 UI,可以做 chrome devtools 沒有的功能和互動。

比如你面試視覺化崗位,你說你對接了 chrome devtools protocol 的 profiler 部分,用 canvas 畫了個火焰圖,會加分很多的。

總結

Chrome 的除錯是透過 WebSocket 和除錯客戶端通訊,制定了 Chrome Devtools Protocol 的協議,Node。js 也是,不過協議叫做 V8 debugger protocol。我們可以透過 protocol monitor 的面板看到所有的 CDP 協議請求響應。

可以實現 CDP 服務端,來對接 chrome devtools 的除錯功能,除錯不同的目標,比如 kraken 渲染引擎。

可以實現 CDP 客戶端,來用不同的工具除錯,比如 vscode debugger、webstorm debugger 等。

我們也可以透過 sdk 的 api 來和 CDP 服務端對接,拿到資料,實現除錯的功能。比如單獨實現 DOM 編輯器、Network 檢視器、JS Debugger、 Profiler 和火焰圖都可以,而且可以做到比 chrome devtools 更強的功能,更好的互動。

當大家想做開源專案沒有資料的時候,不妨考慮下做個 CDP 客戶端,這不比雲音樂專案香麼?