背景
需要分析JS执行的效率,所以需要记录JS的执行时间,通过执行时间分析JS执行效率。但是由于aync/await使用的盛行,造成在记录函数执行时间的过程中,会记录异步执行的时长,造成时间记录不准确,无法分析JS函数真正执行的时间。
看一段代码
const asyncFn = ms => new Promise((resolve, reject) => {
setTimeout(resolve, ms);
});
const record = {
start: 0,
time: 0,
};
const fn = async () => {
record.start = performance.now();
await asyncFn(100);
record.time = performance.now() - record.start;
console.log(record.time);
}
fn();
通过浏览器控制台可以看到输出结果103.84499999781838,每次执行时间可能会不同,但应该都在这个值附近。可以看出由于aync/await函数的存在导致fn函数的计时不准确,把异步函数的执行时间也计算在内了。
在Web端异步函数执行时一般是在请求外部相关接口,此时并不会阻碍Web端执行其他JS函数,不会造成JS阻塞导致页面卡顿,所以这种异步函数的执行时间并不在我们的统计范围内,我们只统计web中代码的执行时间。
修正方式
一般我们可以通过在async/await函数上下分开计时的方式来解决这个问题,具体可以看下段代码:
const asyncFn = ms => new Promise((resolve, reject) => {
setTimeout(resolve, ms);
});
const record = {
start: 0,
time: 0,
};
const fn = async () => {
record.start = performance.now();
record.time = performance.now() - record.start;
await asyncFn(100);
record.start = performance.now();
record.time = performance.now() - record.start;
console.log(record.time);
}
fn();
通过在浏览中运行,可以在控制台中看到结果,大概是0.010000003385357559,可以看出确实可以解决异步函数带来的影响,但是需要在每个涉及async/await的地方都要这样手动处理,你不觉得这样很麻烦吗?
目标
使用babel AST的能力,通过分析代码的AST,自动处理async/await的计时问题,避免人工输入大量重复代码,减少出错的机会。
工具
一个优秀的工具是通往目标的阶梯,而babel当之无愧是这个阶梯。
可视化AST平台
点击跳转,可以很方便查看代码AST结构,有助于理解代码和AST结构之间的关系,事半功倍。
将上面两段代码复制进AST,我们可以看到上述代码的AST结构:
对我们来说,需要重点关注的就是type为Program的部分,这里面描述了代码片段的AST结构。
babel生成AST流程介绍
写babel插件之前,需要对babel的运作周期有个清晰的认识,这样我们才能知道自己写的插件什么时候起作用、达到的效果是什么,写插件的过程中才能游刃有余。
Github上对babel的介绍点击跳转,可以查看对babel插件内容的基本介绍,包括AST中各种节点的定义类型、遍历方式、插件入口等,建议详细查看一遍。由于相关内容,该文档已经比较详细,编写插件过程中,方便进行各种API使用方法的查询手册,因此本文中就不再赘述这部分内容了。
找到处理目标节点
由于本次只是涉及async/await函数相关操作,我们将关注type为AwaitExpression类型的AST节点
babel插件编写格式
按照babel插件的格式,我们需要默认导出一个函数,该函数接收一个babel对象作为参数,返回一个具有visitor属性的对象,具体为:
export default function (babel) {
return {
visitor: {
AwaitExpression(path) {},
},
};
}
在visitor对象中,定义我们需要处理的节点类型进行处理即可,具体逻辑可以参考github上代码
babel插件处理流程
具体流程可以参考github上代码,单元测试部分,主要分为三个部分:
- 解析代码字符串生成AST,主要利用babylon
- 遍历AST,进行节点处理,主要利用babel-traverse,这里为了简便生成需要插入代码的AST,使用了babel-template这个工具,使用起来超级方便,再也不用自己手动使用babel-types去手动构建所需要的AST了
- 根据处理后的AST生成代码,主要利用babel-generator
总结
这样一个简单的babel插件就完成了,当然要是真实环境进行使用的话,还需要考虑很多其他边界条件,这里从整体上介绍babel的插件编写模式,便于后续有相似需求时,可以快速上手。
插件代码示例
可以在github上找到本文中的代码示例,方便进行效果测试和新插件开发。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!