日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線(xiàn)溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
自己實(shí)現(xiàn)ChromeDevTools的Coverage功能

Chrome DevTools 有一個(gè)覆蓋率檢測(cè)的功能,可以檢測(cè) JS、CSS 代碼里有哪些執(zhí)行了,哪些沒(méi)執(zhí)行。并且還會(huì)在 sources 里標(biāo)記出來(lái)。

創(chuàng)新互聯(lián)建站總部坐落于成都市區(qū),致力網(wǎng)站建設(shè)服務(wù)有成都網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)、網(wǎng)絡(luò)營(yíng)銷(xiāo)策劃、網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站維護(hù)、公眾號(hào)搭建、小程序開(kāi)發(fā)、軟件開(kāi)發(fā)等為企業(yè)提供一整套的信息化建設(shè)解決方案。創(chuàng)造真正意義上的網(wǎng)站建設(shè),為互聯(lián)網(wǎng)品牌在互動(dòng)行銷(xiāo)領(lǐng)域創(chuàng)造價(jià)值而不懈努力!

如下圖,綠色的部分是執(zhí)行過(guò)的,而紅色的部分是沒(méi)執(zhí)行的:

在 sources 面板里可以直接看到哪些代碼沒(méi)執(zhí)行,比如下面的紅色部分就是沒(méi)有執(zhí)行的:

這個(gè)功能還是很有用的,可以幫助我們分析哪些代碼是用不到的,可以進(jìn)行延后加載或者刪掉等優(yōu)化。

在 More Tools 里開(kāi)啟:

使用還是很簡(jiǎn)單的,但它是怎么實(shí)現(xiàn)的呢?

代碼是否運(yùn)行過(guò)的數(shù)據(jù)只有運(yùn)行時(shí)才能得到,所以肯定是 Chrome 暴露出來(lái),傳給 Chrome DevTools 做分析和展示的。

Chrome 和 Chrome DevTools 的通信是通過(guò) CDP(Chrome DevTools Protocol)協(xié)議。

傳輸協(xié)議數(shù)據(jù)有多種信道,遠(yuǎn)程調(diào)試的時(shí)候是通過(guò) WebSocket,嵌入的時(shí)候就直接通過(guò)全局變量了。

Chrome 啟動(dòng)的時(shí)候,可以通過(guò) --remote-debugging-port 指定 ws 服務(wù)的端口:

/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222

我們自己實(shí)現(xiàn)一個(gè) ws 客戶(hù)端連上它,就能拿到所有的 CDP 數(shù)據(jù)。

那我們是否能自己實(shí)現(xiàn)一下 JS、CSS 的覆蓋率檢測(cè)功能呢?

肯定是可以的。

自己實(shí)現(xiàn) ws 客戶(hù)端,傳輸 CDP 協(xié)議數(shù)據(jù)這部分可以用 google 提供的一個(gè)包 chrome-remote-interface。

const CDP = require('chrome-remote-interface');
async function test() {
let client;
try {
client = await CDP({
host: '127.0.0.1',
port: 9222
});
const { Page, DOM, Debugger, Runtime, CSS, Profiler } = client;


} catch(err) {
console.error(err);
}
}
test();

連接上 9229 端口,通過(guò)各個(gè)域的 api 進(jìn)行 CDP 的交互即可。

CDP 協(xié)議分為了很多個(gè)域來(lái)管理,比如 DOM、CSS、Debugger 等:

可以通過(guò) Chrome DevTools 的 Protocol Monitor 來(lái)查看傳輸?shù)膮f(xié)議數(shù)據(jù):

數(shù)據(jù)交互分為兩類(lèi),一類(lèi)是服務(wù)端推送過(guò)來(lái)的事件,另一類(lèi)是向服務(wù)端請(qǐng)求的數(shù)據(jù)。

CDP 介紹完了,接下來(lái)我們實(shí)現(xiàn)下覆蓋率檢測(cè)的功能。

首先,我們要知道頁(yè)面下載了哪些 JS 和 CSS。

這個(gè)是通過(guò)監(jiān)聽(tīng)事件拿到的, CSS.styleSheetAdded 和 Debugger.scriptParsed 這倆事件。

我們監(jiān)聽(tīng)下這倆事件:

const CDP = require('chrome-remote-interface');
async function test() {
let client;
try {
client = await CDP({
host: '127.0.0.1',
port: 9222
});
const { Page, DOM, Debugger, Runtime, CSS } = client;

await Page.enable();
await Debugger.enable();
await DOM.enable();
await CSS.enable();

CSS.on('styleSheetAdded', async (event) => {
debugger;
})
Debugger.on('scriptParsed', async (event) => {
debugger;
})
await Page.navigate({url: 'http://127.0.0.1:8084'});

} catch(err) {
console.error(err);
}
}
test();

因?yàn)橛玫?DOM、CSS、Debugger、Page 域的協(xié)議,所以需要先 enable 一下,只有 enable的功能才會(huì)啟用。

這個(gè)很正常,沒(méi) enable 就不啟用,這樣能節(jié)省性能。

執(zhí)行這段代碼,看下拿到的事件對(duì)象:

事件對(duì)象里是這段 js 的 url 和行列號(hào),再就是 scriptId。

然后再看下 CSS.styleSheetAdded 的事件對(duì)象:

也差不多,只不過(guò)這里是 styleSheetId。

那怎么拿到 CSS 和 JS 的內(nèi)容呢?

這就需要用到別的 api 了。

css 的內(nèi)容是用 CSS.getStyleSheetText 來(lái)拿,傳入 styeleSheetId:

const styleSheetId = event.header.styleSheetId;
const content = await CSS.getStyleSheetText({ styleSheetId });

JS 的內(nèi)容是用 Debugger.getScriptSource 來(lái)拿,傳入 scriptId:

const scriptId = event.scriptId;
const content = await Debugger.getScriptSource({ scriptId });

我們把它們按照 id 放到 Map 里:

const cssMap = new Map();
const jsMap = new Map();
CSS.on('styleSheetAdded', async (event) => {
const styleSheetId = event.header.styleSheetId;
const content = await CSS.getStyleSheetText({ styleSheetId });
cssMap.set(styleSheetId, {
meta: event.header,
content: content.text
});
})
Debugger.on('scriptParsed', async (event) => {
const scriptId = event.scriptId;
const content = await Debugger.getScriptSource({ scriptId });

jsMap.set(scriptId, {
meta: event,
content: content.scriptSource
});
})

這樣就能把頁(yè)面上所有的 js 和 css 收集起來(lái):

對(duì)了,測(cè)試頁(yè)面的內(nèi)容是這樣的:







Document







有一個(gè)外部 css:

.aaa {
color: red;
}
div {
color: blue;
}
body {
background: pink;
}

收集到了 JS 和 CSS 的數(shù)據(jù)只是第一步,要計(jì)算出覆蓋率數(shù)據(jù),還要知道哪些 JS 和 CSS 執(zhí)行了。

這個(gè)也有 api:

CSS 開(kāi)啟執(zhí)行數(shù)據(jù)的收集是用 CSS.startRuleUsageTracking:

await CSS.enable();
await CSS.startRuleUsageTracking();

然后一段時(shí)間后 stop:

// 延遲一段時(shí)間再獲取數(shù)據(jù),等頁(yè)面渲染完
await new Promise(resolve => setTimeout(resolve, 3000));
const cssCoverage = await CSS.stopRuleUsageTracking();

這樣就能獲取 CSS 的執(zhí)行數(shù)據(jù):

返回的結(jié)果顯示 scriptId 為 89607.4 的 css 的 50 到 80 個(gè)字符的代碼執(zhí)行了。

我們?cè)?cssMap 里看下這個(gè) id 對(duì)應(yīng)的代碼:

然后取出 50 到 80 個(gè)字符的代碼:

也就是說(shuō)所有 css 里只有這一段代碼是生效的:

你用 Chrome DevTools 的 Coverage 分析結(jié)果也是這樣的:

有了所有 CSS 代碼的數(shù)據(jù),有了執(zhí)行了哪些 CSS 的代碼的數(shù)據(jù),覆蓋率的計(jì)算不就很簡(jiǎn)單了么?

我們?cè)賮?lái)看下 JS 的:

JS 使用 Profiver 的 prociseCoverage 的 api 獲取覆蓋率數(shù)據(jù):

await Profiler.enable();
await Profiler.startPreciseCoverage();
// 延遲一會(huì)再獲取數(shù)據(jù),等 js 執(zhí)行完
await new Promise(resolve => setTimeout(resolve, 3000));
const jsCoverage = await Profiler.takePreciseCoverage();

可以看到返回了兩個(gè) script 的執(zhí)行數(shù)據(jù):

因?yàn)槲覀冺?yè)面上就兩個(gè) script 嘛:

第一個(gè) script 有 4 個(gè) functions:

有同學(xué)說(shuō),不對(duì)呀,不是 add、minus、multiply 3 個(gè)嗎?

那個(gè)沒(méi)有名字的代表 script 的匿名代碼塊。

每個(gè) function 都記錄了字符的范圍,還有執(zhí)行的次數(shù):

比如 add 函數(shù)執(zhí)行了 1 次:

minus 函數(shù)執(zhí)行了 0 次:

第二個(gè) script 的匿名代碼塊執(zhí)行了 1 次:

這不就和 Chrome DevTools 的 Coverage 結(jié)果對(duì)上了么:

不管是覆蓋率數(shù)據(jù)也好,還是在 sources 里可視化展示哪些代碼沒(méi)執(zhí)行也好,都很容易實(shí)現(xiàn)。

這部分的全部代碼如下,感興趣的同學(xué)可以試試:

const CDP = require('chrome-remote-interface');
async function test() {
let client;
try {
client = await CDP({
host: '127.0.0.1',
port: 9222
});
const { Page, DOM, Debugger, Runtime, CSS, Profiler } = client;
await Page.enable();
await Debugger.enable();
await DOM.enable();
await CSS.enable();
await Profiler.enable();
const cssMap = new Map();
const jsMap = new Map();
CSS.on('styleSheetAdded', async (event) => {
const styleSheetId = event.header.styleSheetId;
const content = await CSS.getStyleSheetText({ styleSheetId });
cssMap.set(styleSheetId, {
meta: event.header,
content: content.text
});
})
Debugger.on('scriptParsed', async (event) => {
const scriptId = event.scriptId;
const content = await Debugger.getScriptSource({ scriptId });

jsMap.set(scriptId, {
meta: event,
content: content.scriptSource
});
})
await CSS.startRuleUsageTracking();
await Profiler.startPreciseCoverage();

await Page.navigate({url: 'http://127.0.0.1:8084'});

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

const cssCoverage = await CSS.stopRuleUsageTracking();
const jsCoverage = await Profiler.takePreciseCoverage();
debugger;
} catch(err) {
console.error(err);
}
}
test();

有的同學(xué)可能問(wèn)了,Chrome DevTools 會(huì)用不就行了么,我管它怎么實(shí)現(xiàn)的干嘛?

確實(shí),大多數(shù)業(yè)務(wù)開(kāi)發(fā)同學(xué)會(huì)用 Chrome DevTools 就行了,但是如果你要實(shí)現(xiàn)一個(gè)調(diào)試工具呢?那就要深入理解它的原理了。而且理解了原理,你再去用也更加得心應(yīng)手。

更重要的是,通過(guò) api 的方式,你是能拿到運(yùn)行時(shí)的數(shù)據(jù)的,可以自己做一些計(jì)算和處理,然后把數(shù)據(jù)存下來(lái)之類(lèi)的。

不知道大家有沒(méi)有聽(tīng)說(shuō)過(guò) lighthouse,就是分析頁(yè)面性能、可訪(fǎng)問(wèn)性等等數(shù)據(jù),然后給出一個(gè)得分和優(yōu)化建議的工具:

它其實(shí)是有獨(dú)立的 cli 的:

在 cli 里怎么收集網(wǎng)頁(yè)的數(shù)據(jù),然后做分析呢?

其實(shí)它就是通過(guò) Chrome 運(yùn)行網(wǎng)頁(yè),然后 CDP 的方式收集各種數(shù)據(jù),然后做分析和展示的。

如果某一天,你也要做一個(gè)網(wǎng)頁(yè)分析工具,是不是也可以通過(guò) CDP 的方式來(lái)獲取一些網(wǎng)頁(yè)運(yùn)行數(shù)據(jù)做分析呢?

所有 Chrome DevTools 的數(shù)據(jù),你通過(guò) CDP 都是能拿到的,能做的事情有很多。

總結(jié)

Chrome DevTools 有 Coverage 面板,可以分析 JS 和 CSS 代碼執(zhí)行的覆蓋率,分析出哪些代碼沒(méi)執(zhí)行,然后做后續(xù)優(yōu)化。

這是 Chrome 通過(guò) CDP 暴露給 Chrome DevTools 的,而 CDP 的數(shù)據(jù)我們也能自己實(shí)現(xiàn) ws 客戶(hù)端來(lái)拿到,那自然也可以自己實(shí)現(xiàn)覆蓋率的計(jì)算。

我們通過(guò) chrome-remote-interface 的不同域的 api 來(lái)進(jìn)行了 CSS 和 JS 的代碼的收集,代碼執(zhí)行數(shù)據(jù)的收集,有了這些數(shù)據(jù)就能輕松算出覆蓋率。

lighthouse 的 cli 就是通過(guò)這種方式來(lái)收集 Chrome 運(yùn)行時(shí)數(shù)據(jù),做分析和展示的。如果我們想做一個(gè)調(diào)試工具,或者網(wǎng)頁(yè)分析工具,也可以用類(lèi)似的思路。

Chrome DevTools 能做的所有事情,我們都能自己實(shí)現(xiàn),因?yàn)?CDP 數(shù)據(jù)是一摸一樣的。

你還對(duì)啥 Chrome DevTools 的功能感興趣呢?不如我們自己來(lái)實(shí)現(xiàn)一下?


當(dāng)前文章:自己實(shí)現(xiàn)ChromeDevTools的Coverage功能
文章網(wǎng)址:http://www.5511xx.com/article/ccieche.html