生产环境部署es6代码

时间流转,来到了9102年的末尾,距离es6正式发布已经过去了4年半。在前端发展的时间长河中,我们送别了YUI,ie(也许),jQuery,现在,是时候送别es5了。

收益在哪

程序员在进行技术决策的时候,通常的目的是为了kpi升值加薪这个技术很流行,不,当然是为了对业务产生价值。

不难发现,直接部署es6代码可以带来的好处包括:

  • 代码体积减小
  • 性能提升
  • 缩短构建时间

代码体积减小

首先,es6带来了新的语法和特性,这可以让代码更简洁,使得代码量减少。其次,babel转译之后,会产生一些helper,引入一些polyfill,而且有一些语法特性无法在运行时进行处理,必须在转译过程中修改源代码,这也会导致代码量增加。当然,部署es6代码也需要babel转译一部分更新的语法,并不是说完全不使用babel。

一个Google工程师的试验结果,es6代码的bundle size比es5代码减少了50%。而我自己的实践的结果没有这么夸张,是25%左右

version bundle size Gzipped
es5 221kb 39kb
es6 170kb 29kb

之所以我和他的测试结果差异较大,是因为最终的结果跟每个人的代码风格和代码内容有很大的关系。我用来进行测试的代码是一个线上项目的代码,我个人的代码风格是大量使用es6/7/8语法,不过项目本身大量是在写业务逻辑,并且项目使用了Vue,其实很多js代码是模板编译之后生成的渲染函数。

所以,大概的结论是es6的代码会比es5的代码体积减少15% ~ 50%,具体能减少多少,取决于代码风格以及代码内容。代码风格越现代,代码中”生成的代码”越少,收益越高。

性能提升

es6代码相对于es5代码,性能更高的原因我认为有2个

  • 代码量减少带来的解析时间减少,这个正比于代码体积的减少
  • 运行性能的提高

对于第一点,浏览器解析代码时间的减少应该占比较小,通过chrome的Performance面板可以看到,解析一个200kb的js文件Compile Script耗时为10ms(测试机器为台式机,i7/16G)。

对于第二点,运行时性能。在es6刚刚发布的时候,很多新特性的性能是比较低的,因为js引擎没有足够的时间去进行优化,相比较而言,es5以及更老的代码经过了浏览器的长时间优化,在es6刚出来的时候,很对人也对es6的性能有很大的担忧。

Github上有一个仓库,专门对es6和es5进行了性能对比。

从对比结果可以看出来,在chrome 72版本上,es6代码的性能优于babel转译成的es5代码,和手写的es5代码比起来各有千秋,基本算是55开。

而且,浏览器对于es6的性能优化是持续性的,最近V8就会因为React hooks而改进数组解构的性能。

针对运行时的es6代码和es5代码的性能对比,我也用一个线上项目进行了实验。实验方式如下

  1. 利用performance API 在打包后的app.js文件开头记下时间戳,在js文件末尾减去开始的时间,得到一个时间,众所周知,打包之后的app.js是一个立即执行函数,所以这个时间包含了app.js文件中部分代码的运行时间
  2. 利用chrome 的 Performance面板,可以直接得到一段js的执行时间Evaluate Script

evaluate-script.png

实验结果如下(20次的平均值)

version 记录的运行时间 Performance面板的Evaluate Script
es5 258.88ms 295.29ms
es6 206.28ms 241.59ms

测试条件下,es6的代码取得了20%左右的运行性能提升

风险在哪儿

js的运行环境非常复杂,桌面端、移动端、各种小程序、各种webview、node.js,能否部署es6代码只能依靠自己判断。

就我个人的经验而言,大部分的中后台项目都具备直接部署es6代码的条件,而且我们在具体的实施中肯定会有降级方案,让不支持es6的情况下运行es5的代码。

如何实施

Vue用户可以通过Vue cli的 –modern直接开启现代模式

非Vue使用者,可以通过这篇文章提到的方案来进行。大概就是利用script标签的module type作为浏览器是否全面支持es6的检测,并通过type=nomodule来进行降级处理。

1
2
3
4
5
// 不支持module的浏览器,下载但不会执行
<script type="module" src="es6.js"></script>

// 支持module的浏览器,不会下载
<script nomodule src="es5.js"></script>

一个需要注意的点是safari 10不支持nomodule,所以需要针对它解决重复下载并执行的问题。(ps: safari浏览器是新时代的毒瘤)

虽然,一个降级的方案可以保证我们的代码可以在只支持es5的浏览器上也可以执行,但是同时这些老的浏览器会下载2份代码,带来的损失非常大,因为老设备通常也意味着低性能和低网速,它们更不能承受性能损失。所以我认为,如果你的业务需要兼容es5的用户达到了20%以上,我就不赞同采用这个方案。

如果可以确定完全不需要兼容es5的用户,可以直接修改browserlist到全面支持es6的浏览器版本,并且不用考虑降级方案,此时还会带来构建速度提升这一额外的好处。

browserslist示例

1
2
3
4
5
Chrome >= 60
Safari >= 10.1
iOS >= 10.3
Firefox >= 54
Edge >= 15

结语

时间带走一切,es5也不例外。

参考