代码覆盖率在性能优化上的一种可行应用

简介:JavaScript 是前端应用主要语言,相较于其他平台编程语言,JS资源多数情况下要通过网络进行加载,那么代码的体积直接影响了页面加载执行时间。“无效的代码”的多寡直接影响到了我们的代码质量,所以度量代码的执行覆盖率是一项重要的优化前置工作。

You can't manage what you can't measure.
一件事如果你无法衡量它,你就无法管理它。——管理大师 彼得·德鲁克

前言

JavaScript 是前端应用主要语言,相较于其他平台编程语言,JS资源多数情况下要通过网络进行加载,那么代码的体积直接影响了页面加载执行时间。“无效的代码”的多寡直接影响到了我们的代码质量,所以度量代码的执行覆盖率是一项重要的优化前置工作。

什么是代码覆盖率

1、Dead code

Dead code 也叫无用代码,这个概念应是在编译时静态分析出的对执行无影响的代码,举个例子:

// a.js
const a = 1;
const b = 2; /* dead code */
export default a;
// index.js
import a from './a.js';
export default function() {console.log(a);
}

通常我们用 Tree Shaking 在编译时移除这些 dead code以减小代码体积。

2、冗余代码

而代码覆盖率里所提到的冗余代码 和 Dead Code 又略有不同,简单来说Dead code适用于编译时,而 Code coverage 适用于运行时。
Dead code 是任何情况下都不会执行的代码,所以可以再编译阶段将其剔除。
冗余代码  是某些特定的业务逻辑之下并不会执行到这些代码逻辑(比如:在首屏加载时,某个前端组件完全不会加载,那么对于“首屏”这个业务逻辑用例来讲,该前端代码就是冗余的)

3、代码覆盖率

代码覆盖率(Code coverage)是软件测试中的一种度量指标。即描述测试过程中(运行时)被执行的源代码占全部源代码的比例。

怎么度量代码覆盖率

1、Chrome 浏览器 Dev Tools

chrome 浏览器的 DevTools 给我们提供了度量页面代码(JS、CSS)覆盖率的工具 Coverage。

  • 使用方式:Dev tools —— More tools —— Coverage

  • 可度量代码类型:JS CSS
  • 统计可视化形式:
  • 使用率是以byte字节来计算的;
  • 当我们选择一段脚本资源即可在 Source 栏可以看到加载页面时当前资源 run过得代码(蓝色)和没有run过得代码(红色);
  • 缺点:显然,目前大部分网页上的JS脚本基本都是经过混淆压缩打包过后的产物,对于开发者而言,这种覆盖率可读性及参考价值不大。

TIPS:当然,如果在拥有 source map 的情况下也是可以用浏览器查看源代码的覆盖率的:

  1. 在 source tab 中找到当前页面的 js 资源文件(当然已经被混淆的面目全非)

  1. 输入 sourcemap URL(以 def 发布平台为例,在构建结果中可找到)

  1. webpack:// 目录下即可查看对应源码的大致覆盖率(不过没有什么消费价值)

那么问题来了,有没有一种方法可以令开发者了解 源代码 的代码覆盖率的值呢?

2、Istanbul(NYC)

这个软件以土耳其最大城市伊斯坦布尔命名,因为土耳其地毯世界闻名,而地毯则是用来覆盖的。

Istanbul 或者 NYC(New York City,基于 istanbul 实现) 是度量 JavaScript 程序的代码覆盖率工具,目前绝大多数的node代码测试框架使用该工具来获得测试报告,其有四个测量维度:

line coverage(行覆盖率-每一行是否都执行了) 【一般我们关注这个信息】
function coverage(函数覆盖率-每个函数是否都调用了)
branch coverage(分支覆盖率-是否每个 if 代码块都执行了)
statement coverage(语句覆盖率-是否每个语句都执行了)
  • 可以度量的代码类型:JS TS
  • 统计可视化的形式:
  • HTML
  • terminal
  • 缺点:目前使用 istanbul 度量网页前端JS代码覆盖率没有非侵入的方案,采用的是在编译构建时修改构建结果的方式埋入统计代码,再在运行时进行统计展示。

我们可以使用 babel-plugin-istanbul 插件在对源代码在 AST 级别进行包装重写,这种编译方式也叫 代码插桩 / 插桩构建(instrument)

3、插桩构建

我们如果要度量这一段代码哪些代码执行了 哪些代码没有执行,我们会怎么做呢?

// add.js
function add(a, b) {return a + b
}
module.exports = { add }

我们可以很容易的想到加一些“装饰性”的代码在我们的源码里面,那么当代码一行一行的执行到某处时,那么我们就在全局环境变量中记录一下:

// 全局对象记录了 __coverage__ 记录了上面代码中的语句和函数的执行次数
const c = (window.__coverage__ = {// "f" 表示每一个 function 被执行的次数// 当前代码只有一个 function 因此,f 数组只有一个 且记录值为 0f: [0],// "s" 表示每一个 statement 被执行的次数// 3 个 statement 全部都以 0 赋值s: [0, 0, 0],})// 函数定义是一个语句(statement),那么我们 +1
c.s[0]++function add(a, b) {// 如果 add 函数(function)被调用,f +1,且改调用语句 s +1c.f[0]++c.s[1]++return a + b}
// add 被调出语句 s +1
c.s[2]++
module.exports = { add }

且 istabul 确实也是这么做的,babel-plugin-istanbul 在构建过程中分析 AST 并将相应统计单元(语句、函数、分支等)做装饰代码的添加,最终在代码运行之后,输出一份 json 格式的数据:

{"/Users/bairuobing/test/istanbul.js":{"path":"/Users/bairuobing/test/istanbul.js","s":{"1":1,"2":0,"3":1},"b":{},"f":{"1":0},"fnMap":{ // function 的开始结束位置信息"1":{"name":"add","line":1,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":19}}}},"statementMap":{ // statement 的开始结束位置信息"1":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},"2":{"start":{"line":2,"column":4},"end":{"line":2,"column":16}},"3":{"start":{"line":4,"column":0},"end":{"line":4,"column":24}}},"branchMap":{ // branch 的开始结束位置信息}}
}

当我们在运行代码过后,得到了上面的 json 便可以消费它了。

# terminal 形式输出
nyc report --reporter=text
# HTML 形式输出
nyc report --reporter=lcov --exclude-after-remap=false
  • terminal

  • HTML

代码覆盖率在 iHome Rax开发套件 Tbox 中的应用

tips:tbox 每平每屋 消费者端 本地开发套件

既然我们知道了源代码的代码覆盖率,我们可以用它为性能优化做些什么贡献呢?

当工程主 bundle 较大,那么采用拆包较大的/无用的前端组件来瘦身首屏主 JS 包不失为一种可行的选择,此时就可以根据代码覆盖率来决定优化哪些代码。

1、代码分割

React.lazy 已经为我们提供了一种不错的思路,就是利用动态加载模块规范 import()(webpack对import()解析为代码分割)的能力来实现前端组件代码懒加载/动态加载。

以此为灵感,那么为何不将某些组件通过动态引入的方式加载,来以此换取首页 bundle 的瘦身呢?

// 动态引入组件
// ThisIsBigMod
import { createElement, useState, useEffect } from 'rax';
export default (props) => {const [AsyncMod, setAsyncMod] = useState(null);useEffect(() => {const load = async () => {const Module = await import('./ThisIsBigMod'); // 关键try {setAsyncMod(Module);} catch (e) {console.log(e);}};load();}, []);if (!AsyncMod || !AsyncMod.default) {return null;}return <AsyncMod.default {...props} />;
};

2、下一步

我们能通过代码覆盖率统计出哪些组件的代码首屏使用率为0(或者门槛值30%以下),并在项目工程中自动生成一个持久化的文件配置(app.json中),之后依据配置将这些低使用率的组件代码在生产构建时将产物代码改写为动态引入。

于是有了以下方案:

3、如何使用

  1. 该功能需要项目下安装以下 build 插件:
  • @ali/build-plugin-coverage
  • @ali/build-plugin-async-components
tnpm install --save-dev @ali/build-plugin-coverage  @ali/build-plugin-async-components
  1. build.json
// build.json
"plugins": [......"@ali/build-plugin-coverage",["@ali/build-plugin-async-components",{"active": true}]
]

运行 Tbox:

  1. 插桩构建
  • 依赖 @ali/build-plugin-coverage
  • 通过插桩将源码中插入统计代码
  • 本地构建之后页面全局会注入__coverage__变量(可在页面控制台输出该变量检查插桩是否成功)

  1. 分析自动化生成配置
  • 等待完成首屏渲染(或者完成自定义的一系列行为用例),此刻插桩代码已经完成了代码使用率的统计

  • 打开 Tlog 小工具 点击代码优化->生成源代码优化配置,此刻 Tbox 本地服务已经接收到了发来的__coverage__并完成后续的代码覆盖率分析,通过分析使用率低于门槛值的组件文件,将这些组件的项目相对路径写入 app.json 的 modsPath 字段下
  • 此刻 @ali/build-plugin-async-components 会根据 modsPath 配置自动将组件构建为动态引入的方式

  • 如果您想通过自己的配置来完成组件异步化,请直接手动修改 app.json 里的 modsPath 字段,只需依赖 @ali/build-plugin-async-components 插件再次构件即可

  • 此时我们条件加载被异步化的组件会发现,BigMod 组件已经被动态的拆包引入了,页面主 js 包也得到了瘦身,搞定!

写在最后

istanbul 在 node 环境下跑测试用例代码能度量覆盖率是由于其对运行时模块加载器的源代码拦截,但是比较遗憾的是,本文介绍的代码插桩分析覆盖率这会引入一些多余的桩代码,或许采用 puppeteer 无头浏览器提供的Coverage api + sourceMap 逆编译的思路来进行度量是一种更加完美的方式,期待与诸君一起探索,继续努力!

原文链接

本文为阿里云原创内容,未经允许不得转载。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/510894.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MaxCompute湖仓一体介绍

简介&#xff1a;本篇内容分享了MaxCompute湖仓一体介绍。 分享人&#xff1a;孟硕 阿里云 MaxCompute产品专家 视频链接&#xff1a;数据智能实战营-北京站 专题回顾 正文&#xff1a; 本篇内容将通过两个部分来介绍MaxCompute湖仓一体。 一、什么是 MaxCompute 湖仓一体…

云原生离线实时一体化数仓建设与实践

简介&#xff1a;本篇内容分享了云原生离线实时一体化数仓建设与实践。 分享人&#xff1a;刘一鸣 Hologres 产品经理 视频链接&#xff1a;数据智能实战营-北京站 专题回顾 正文&#xff1a; 本篇内容将通过五个部分来介绍云原生离线实时一体化数仓建设与实践。 一、离线实…

议题征集|Flink Forward Asia 2022 正式启动

在这数据量爆炸性增长的时代&#xff0c;开源软件如雨后春笋般出现在开发者的视野中&#xff0c;数据的价值被重新定义。同时&#xff0c;越来越多的企业开启实时化道路&#xff0c;数据的实时分析与计算需求与日俱增。作为主打流处理的计算引擎 Apache Flink 于 2014 年正式开…

龙蜥正式开源 SysOM:百万级实战经验打造,一站式运维管理平台 | 龙蜥技术

简介&#xff1a;SysOM集监控、告警、诊断、修复、安全能力于一体的操作系统运维平台。 文/系统运维 SIG 如果你被突如其来的 OOPS 和满屏奇怪的函数弄得满头问号&#xff1f;机器内存明明很大&#xff0c;却申请不出来内存&#xff1f;业务周期抖动&#xff0c;ping 命令偶尔…

微软在华商业应用战略全面升级,首次推出面向医疗和生命科学的云行业套件

2022年9月29日&#xff0c;微软宣布进一步升级在华商业应用战略&#xff0c;落地一系列智能商业应用&#xff08;Biz App&#xff09;功能的同时&#xff0c;以Dynamics 365和Power Platform为基础&#xff0c;进一步完善商业应用战略与价值定位&#xff0c;助力更多客户和合作…

使用Databricks进行零售业需求预测的应用实践

简介&#xff1a;本文从零售业需求预测痛点、商店商品模型预测的实践演示&#xff0c;介绍Databricks如何助力零售商进行需求、库存预测&#xff0c;实现成本把控和营收增长。 作者&#xff1a;李锦桂 阿里云开源大数据平台开发工程师 本文从零售业需求预测痛点、商店商品模型…

龙蜥开源内核追踪利器 Surftrace:协议包解析效率提升 10 倍 | 龙蜥技术

简介&#xff1a;如何将网络报文与内核协议栈清晰关联起来精准追踪到关注的报文行进路径呢&#xff1f; 文/系统运维 SIG Surftrace 是由系统运维 SIG 推出的一个 ftrace 封装器和开发编译平台&#xff0c;让用户既能基于 libbpf 快速构建工程进行开发&#xff0c;也能作为 ft…

开源要正式写进法律了?

作者 | 何苗 出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;去年&#xff0c;当大家还在为开源的快速发展而欢呼之际&#xff0c;影响了全球数百万台计算机Log4j 漏洞事件给开源软件开发者与使用者敲响了一记警钟。因而今年&#xff0c;开源软件及其供应链安全…

阿里云软著申请|这项保护,让我得到了10万赔偿

简介&#xff1a;对于企业来说&#xff0c;申请软件著作权是证明自己和保护自己的强力护盾。除此之外&#xff0c;它还有着很多不可忽视的意义与价值。阿里云软著申请&#xff0c;一站式智能服务&#xff0c;助力企业和开发者高效发展&#xff0c;省时省力更省心。 前几日&…

宜搭小技巧|海量数据管理难?这招帮你事半功倍

简介&#xff1a;一键生成数据管理页&#xff0c;海量数据随心管理&#xff01; 话接上回&#xff0c;宜小搭组织大家团建&#xff0c;当收集完大家的报名信息后&#xff0c;有小伙伴想要修改已提交的信息&#xff0c;面对海量的数据&#xff0c;整理查找太费时间。 如何快速…

1024 程序员节官方剧透:重磅大咖再聚,共话中国技术新生态

在二进制垒起的计算机世界里&#xff0c;1024 对于程序员而言&#xff0c;早已不再是单纯的一串数字&#xff0c;不断演进的开发时代赋予了它特殊的意义。 伴随着一份份热衷与期盼&#xff0c;10 月 22-24 日&#xff0c;由湖南湘江新区管委会主办&#xff0c;长沙工业与信息化…

前端性能优化实战

简介&#xff1a;引用彼得德鲁克的一句话&#xff0c;“You cant manage what you cant measure。一件事如果你无法衡量它、你就无法管理它”&#xff0c;性能同样如此。如果没有一个准确的方案来对性能进行度量&#xff0c;那优化就无从谈起。那么对于我们来说&#xff0c;哪些…

Elastic与阿里云助力汽车及出行产业数字化转型

简介&#xff1a;目前&#xff0c;阿里云和Elastic在全国已经有很多的项目正在开展合作&#xff0c;而在移动出行领域与享道出行的合作案例&#xff0c;则是代表性的。 在汽车产业变革逐步深入的当下&#xff0c;云计算、大数据等信息技术成为了汽车企业经历数字化转型时的“刚…

企业版Spark Databricks + 企业版Kafka Confluent 联合高效挖掘数据价值

简介&#xff1a;本文介绍了如何使用阿里云的Confluent Cloud和Databricks构建数据流和LakeHouse&#xff0c;并介绍了如何使用Databricks提供的能力来挖掘数据价值&#xff0c;使用Spark MLlib构建您的机器学习模型。 前提条件 已注册阿里云账号&#xff0c;详情请参见阿里云…

解决微服务架构下流量有损问题的实践和探索

简介&#xff1a;绝⼤多数的软件应⽤⽣产安全事故发⽣在应⽤上下线发布阶段&#xff0c;尽管通过遵守业界约定俗成的可灰度、可观测和可滚回的安全⽣产三板斧&#xff0c;可以最⼤限度的规避发布过程中由于应⽤⾃身代码问题对⽤户造成的影响。但对于⾼并发⼤流量情况下的短时间…

5月25日,阿里云开源 PolarDB-X 将迎来升级发布

简介&#xff1a;2022年5月25日&#xff0c;阿里云开源 PolarDB-X 将升级发布新版本&#xff01;PolarDB-X 从 2009 年开始服务于阿里巴巴电商核心系统&#xff0c; 2015 年开始对外提供商业化服务&#xff0c;并于 2021 年正式开源。本次发布会将重磅推出在稳定性、生态融合以…

技术分享丨云企业网CEN2.技术揭晓

简介&#xff1a;随着企业数字化转型的加速&#xff0c;越来越多的企业选择了将业务部署在云上&#xff0c;这其中有超过20%的企业有全球组网的需求&#xff0c;这就使得云上网络的规模越来越大&#xff0c;复杂度也越来越高&#xff0c;为了应对这些变化&#xff0c;阿里云推出…

MAE 自监督算法介绍和基于 EasyCV 的复现

简介&#xff1a;自监督学习&#xff08;Self-Supervised Learning&#xff09;能利用大量无标注的数据进行表征学习&#xff0c;然后在特定下游任务上对参数进行微调。通过这样的方式&#xff0c;能够在较少有标注数据上取得优于有监督学习方法的精度。近年来&#xff0c;自监…

企业实践|分布式系统可观测性之应用业务指标监控

简介&#xff1a;本文主要讲述如何建立应用业务指标Metrics监控和如何实现精准告警。Metrics 可以翻译为度量或者指标&#xff0c;指的是对于一些关键信息以可聚合的、数值的形式做定期统计&#xff0c;并绘制出各种趋势图表。透过它&#xff0c;我们可以观察系统的状态与趋势。…

1024 程序员节城市嘉年华,共话技术生涯的一万种可能!

更硬核的技术峰会&#xff0c;更多元的主题论坛&#xff0c;更丰富的科技元素……更热血的 1024 程序员节闪亮登场&#xff01;由湖南湘江新区管委会主办&#xff0c;长沙工业与信息化局、长沙信息产业园管委会与 CSDN 联合承办的第三届 2022 1024 程序员节将于 10 月 22 - 24 …