自己实现 Chrome DevTools 的 Coverage 功能

网站建设3年前发布
36 0 0

20230306101701757d2b28634c38412ff164c55bbe5132783171753,Chrome DevTools 有一个覆盖率检测的功能,可以检测 JS、CSS 代码里有哪些执行了,哪些没执行。并且还会在 sources 里标记出来。,如下图,绿色的部分是执行过的,而红色的部分是没执行的:,2023030610170266bad150499288bb2b2544a5c0da42f06245ac945,在 sources 面板里可以直接看到哪些代码没执行,比如下面的红色部分就是没有执行的:,2023030610170209ff6f506ac94639977195e326c8278a39ab20317,这个功能还是很有用的,可以帮助我们分析哪些代码是用不到的,可以进行延后加载或者删掉等优化。,在 More Tools 里开启:,20230306101942d9f47fb155148524ee056397ec4018740e69c0675,使用还是很简单的,但它是怎么实现的呢?,代码是否运行过的数据只有运行时才能得到,所以肯定是 Chrome 暴露出来,传给 Chrome DevTools 做分析和展示的。,Chrome 和 Chrome DevTools 的通信是通过 CDP(Chrome DevTools Protocol)协议。,20230306101703e6f401233540f0eb7a1227996599bbf818f9ab190,传输协议数据有多种信道,远程调试的时候是通过 WebSocket,嵌入的时候就直接通过全局变量了。,Chrome 启动的时候,可以通过 --remote-debugging-port 指定 ws 服务的端口:,我们自己实现一个 ws 客户端连上它,就能拿到所有的 CDP 数据。,那我们是否能自己实现一下 JS、CSS 的覆盖率检测功能呢?,肯定是可以的。,自己实现 ws 客户端,传输 CDP 协议数据这部分可以用 google 提供的一个包 chrome-remote-interface。,连接上 9229 端口,通过各个域的 api 进行 CDP 的交互即可。,CDP 协议分为了很多个域来管理,比如 DOM、CSS、Debugger 等:,2023030610170496272b859e192b34511788da13f6a6720523ee477,可以通过 Chrome DevTools 的 Protocol Monitor 来查看传输的协议数据:,20230306101704a97aa212545d47ad22769293ec37869f4b8b45556,数据交互分为两类,一类是服务端推送过来的事件,另一类是向服务端请求的数据。,CDP 介绍完了,接下来我们实现下覆盖率检测的功能。,首先,我们要知道页面下载了哪些 JS 和 CSS。,这个是通过监听事件拿到的, CSS.styleSheetAdded 和 Debugger.scriptParsed 这俩事件。,我们监听下这俩事件:,因为用到 DOM、CSS、Debugger、Page 域的协议,所以需要先 enable 一下,只有 enable的功能才会启用。,这个很正常,没 enable 就不启用,这样能节省性能。,执行这段代码,看下拿到的事件对象:,20230306101942164fb901744f510a3c51353d5bdc67f953dfea459,事件对象里是这段 js 的 url 和行列号,再就是 scriptId。,然后再看下 CSS.styleSheetAdded 的事件对象:,20230306101705c828fb9782810fe16d977518a2d5a59792bdfa182,也差不多,只不过这里是 styleSheetId。,那怎么拿到 CSS 和 JS 的内容呢?,这就需要用到别的 api 了。,css 的内容是用 CSS.getStyleSheetText 来拿,传入 styeleSheetId:,JS 的内容是用 Debugger.getScriptSource 来拿,传入 scriptId:,我们把它们按照 id 放到 Map 里:,这样就能把页面上所有的 js 和 css 收集起来:,20230306101706925047f80c10a9bebbc1665316bfa8bf5e7c5030620230306101707f99c41246732d6563661616298da4da65ba9ce804,对了,测试页面的内容是这样的:,有一个外部 css:,收集到了 JS 和 CSS 的数据只是第一步,要计算出覆盖率数据,还要知道哪些 JS 和 CSS 执行了。,这个也有 api:,CSS 开启执行数据的收集是用 CSS.startRuleUsageTracking:,然后一段时间后 stop:,这样就能获取 CSS 的执行数据:,2023030610170815f110a14fba4f477b265474c7462e445d63d8676,返回的结果显示 scriptId 为 89607.4 的 css 的 50 到 80 个字符的代码执行了。,我们在 cssMap 里看下这个 id 对应的代码:,20230306101944b8e9c15365281ee4a5c9327239da0a426d7b83210,然后取出 50 到 80 个字符的代码:,20230306101708757b08f13a329325479339bbdd1db497afc114523,也就是说所有 css 里只有这一段代码是生效的:,20230306101944d350324850cf1324cd920364f0c3f9c0a898eb384,你用 Chrome DevTools 的 Coverage 分析结果也是这样的:,202303061017091299b9f49bc1464edf23932c48d7bd55d9256a318,有了所有 CSS 代码的数据,有了执行了哪些 CSS 的代码的数据,覆盖率的计算不就很简单了么?,我们再来看下 JS 的:,JS 使用 Profiver 的 prociseCoverage 的 api 获取覆盖率数据:,可以看到返回了两个 script 的执行数据:,20230306101710f2a70bd38b1ea7f18c3388dfcf5706f9275cba960,因为我们页面上就两个 script 嘛:,20230306101710a42e3b652269d12422e8731fd78de9ae0ff97e332,第一个 script 有 4 个 functions:,202303061017114177bce79188765f0cc228b6fa49369ba6ccfa391,有同学说,不对呀,不是 add、minus、multiply 3 个吗?,那个没有名字的代表 script 的匿名代码块。,每个 function 都记录了字符的范围,还有执行的次数:,比如 add 函数执行了 1 次:,20230306101712624f0e1667f60bf5398151db06d3d2be6fa5c2813,minus 函数执行了 0 次:,20230306101713618d154123440c22d404142a02e47fa464701e447,第二个 script 的匿名代码块执行了 1 次:,20230306101713e2d603846f56167c64d427305da9bf7f9ed024408,这不就和 Chrome DevTools 的 Coverage 结果对上了么:,20230306101945c65ef5e5216177d1e42045013f955b69f7f23c686,不管是覆盖率数据也好,还是在 sources 里可视化展示哪些代码没执行也好,都很容易实现。,这部分的全部代码如下,感兴趣的同学可以试试:,有的同学可能问了,Chrome DevTools 会用不就行了么,我管它怎么实现的干嘛?,确实,大多数业务开发同学会用 Chrome DevTools 就行了,但是如果你要实现一个调试工具呢?那就要深入理解它的原理了。而且理解了原理,你再去用也更加得心应手。,更重要的是,通过 api 的方式,你是能拿到运行时的数据的,可以自己做一些计算和处理,然后把数据存下来之类的。,不知道大家有没有听说过 lighthouse,就是分析页面性能、可访问性等等数据,然后给出一个得分和优化建议的工具:,2023030610171517dd2ec32e8436d1d6f067eee1eddfc55d2c5b284,它其实是有独立的 cli 的:,20230306101946227e4b55658e4e8f26f137f8d9e6e896a11839309,在 cli 里怎么收集网页的数据,然后做分析呢?,其实它就是通过 Chrome 运行网页,然后 CDP 的方式收集各种数据,然后做分析和展示的。,如果某一天,你也要做一个网页分析工具,是不是也可以通过 CDP 的方式来获取一些网页运行数据做分析呢?,所有 Chrome DevTools 的数据,你通过 CDP 都是能拿到的,能做的事情有很多。,Chrome DevTools 有 Coverage 面板,可以分析 JS 和 CSS 代码执行的覆盖率,分析出哪些代码没执行,然后做后续优化。,这是 Chrome 通过 CDP 暴露给 Chrome DevTools 的,而 CDP 的数据我们也能自己实现 ws 客户端来拿到,那自然也可以自己实现覆盖率的计算。,我们通过 chrome-remote-interface 的不同域的 api 来进行了 CSS 和 JS 的代码的收集,代码执行数据的收集,有了这些数据就能轻松算出覆盖率。,lighthouse 的 cli 就是通过这种方式来收集 Chrome 运行时数据,做分析和展示的。如果我们想做一个调试工具,或者网页分析工具,也可以用类似的思路。,Chrome DevTools 能做的所有事情,我们都能自己实现,因为 CDP 数据是一摸一样的。,你还对啥 Chrome DevTools 的功能感兴趣呢?不如我们自己来实现一下?

© 版权声明

相关文章