[Dry goods] Front-end engineering and performance optimization

As a development, not just the front end, optimization is always something you can't avoid, our goal is to make the product faster. The object of optimization not only refers to the product itself, but also our daily development process. From joining the team to now, about half of the time has been spent on optimization. During the period, I encountered many problems. Looking back, optimization is not that simple, but also trivial. The development process and the ability to continuously optimize the product with relative ease is really not easy. Without the silver bullet, any project takes a lot of time and effort. But any improvement worthy of improvement makes us feel that our efforts are not in vain. Sometimes I just want to be lazy and free from boring repetition.

When I first came in, I added a total of 3 people in my team full-time front-end development. The project is relatively simple, and the predecessors have already done modularization, but they feel that it is not thorough enough. Later, the project gradually became huge, and with the reconstruction of classmates, the number of staff reached 13 when it was at most. Many problems were encountered in this process. The front-end framework evolved three times, all because of some thorny problems and had to make adjustments. There is no absolute good or bad, only appropriateness.

11.0 era

The early modularization has done a good job, at least you don't need to spend a lot of time to refactor the code. The module is divided as shown in the figure below, and the logic level is still relatively clear.

The toss is more than front-end engineering and performance optimization

The mainstream libraries that the front-end modularization relies on are the domestic Seajs and foreign requirejs, which are not stated here. Seajs is used as the module manager, and zepto is used as the basic library file. The lib mainly contains the mainstream third-party library files used in the project.

We know that the biggest drawback of modularization is the increase in the number of HTTP requests , so files must be merged when going online. The package module in the figure below is a large collection of files, and many JS modules are packaged. Excluding the basic library files and business module layer in the figure above, most of the files are packaged in package.js when it goes online.

The toss is more than front-end engineering and performance optimization

The JS request for most pages looks like this:

Students who are more careful may notice two problems: file size and loading time. The screenshot just now was taken on the PC side, and the performance of mobile phones and different network environments will be even worse.

Now look at the table of contents

The toss is more than front-end engineering and performance optimization


Existing problems:

  • The catalog looks standardized, but it is actually a mix of public and business.

  • Most files are merged into one file, and the merge strategy is unreasonable.

  • 由第二点引发的第三个问题,发布上线时,只要两人发布涉及到package文件,冲突必然发生。

  • 发布时需要down下上一次的文件,对照合并的新文件,以免发错。

  • 注意,第四点是人工。一不小心发错,或者把他人刚发布的文件覆盖了,这种事情发生10+次。

  • 只有一台测试机器,测试环境经常覆盖是常事。

  • 版本控制问题,不以SVN为版本,而是预发布机器上代码,管理混乱

不敢想象如果10+人的团队一起在这种模式下开发,会是怎样的场面。

22.0时代

由第一个版本引起的问题,着实让人很蛋疼,每次开发版本就是一次阵痛,尤其是测试、发布环节。所以就开始慢慢着手解决。随着业务扩展,人员增多,就诞生了下面这个图。

The toss is more than front-end engineering and performance optimization


优化措施:

  • 调整模块,让共用的模块更加共用,业务模块跟随业务自身。

  • 更改模块合并策略,既然大了,我就分成小,一定程度缓解了冲突。

  • 替换原有的同步文件工具,包括测试与正式环境,接入ARS,提测发布流程顺畅多了。

  • ARS带有冲突检测功能,告别人工对照合并,覆盖不再容易发生。

  • 公共JS文件缓存在localstorage中,模拟manifest,带版本号控制。

  • 以SVN为板块控制工具,不再对照外网代码。


一些统计

  • localstorage本地缓存

The toss is more than front-end engineering and performance optimization

localstorage缓存命中率

The toss is more than front-end engineering and performance optimization

首屏时间

The toss is more than front-end engineering and performance optimization

window.onload时间

The toss is more than front-end engineering and performance optimization

一切看起来很美好,但是好景不长,因为新的问题又来了。

  1. 之前拆分package.js文件为多个文件,实际请求的时候则是合并了请求,包括JS文件和CSS文件。combo文件实际上会有延迟问题,在发布的时间节点上存在不同步的问题,直接导致页面挂了。

  2. 抛开combo文件不说,由于浏览器缓存的问题,每次更新版本的时候要手动加上一个时间戳,来规避缓存造成的错误。也是个很蛋疼的点。

  3. 随着业务增长,越来越多页面是放在APP里面访问。触屏页面已经不再是重点,如何更好的利用APP加速页面才是关注点。很多人想到了手Q的离线包,但听说实践起来也不是特别方便,我们就采用了客户端缓存hash文件的策略,告别304。所以这里又涉及到自动化。

  4. 雪碧图基本是手工;

  5. 代码混淆没有压缩;

33.0时代

为了解决上述问题,流程需要进一步优化,简单点就是让自动化程度更提高。


3.1 探索期

前期在方案选择上也做过一些讨论,自己完全从底层写时间上不允许。之前折腾过Grunt发现并不是那么好用,后来发现百度的前端解决方案FIS能够满足我们的需求。

  1. 生成以hash值(后缀)命名的文件,代码更改,生成新文件,且都会自动更新HTML中的引用(核心诉求),就像下图:

  2. 合并雪碧图

  3. 压缩混淆文件

  4. 文件合并(包括JS文件和CSS文件)

能做到这几点基本就满足了我们的需求。前期的一切都是未知的,不太明白会遇到什么大问题。乍看起来非常好用,如果简单的页面,确实会很简单,只要简单几行配置就可以搞定,但到现在FIS的配置文件200+行。一些特性很难满足,需要二次开发。上手简单,要深入难,必须要看源码改源码,写插件,这大概就是用FIS的心得。

前期想了要怎样把开发——测试——预发布——发布这个流程依赖工具流畅的跑起来,大概构思如下:

The toss is more than front-end engineering and performance optimization

注:

  1. 调试、发布代码与源代码分离

  2. 本地调试用代理如fiddler,或者上开发机

  3. deploy是构建工具同步文件的一个功能

  4. 保证源码的版本最新,发布代码走ARS。

工程化进展却不是想象中的顺利,实践中遇到了一些问题,也只能硬着头皮咬着牙去解决。


3.2 煎熬期

冲突问题冲突问题一直存在,在2.0时代不那么明显罢了。原因是测试环境的JS已经被合并过一次。

时间问题由于刚开始文件比较少,构建速度基本没啥问题。后来业务越来越多,参与的开发也越来约多。文件暴增到4000+,构建时间一步步增加。开发调试耗时 3987ms

The toss is more than front-end engineering and performance optimization

发布构建的时候因为要进行md5计算,文件压缩等,要181745ms!已经无法忍了。

ARS流程用过ARS的同学肯定明白,流程还是比较蛋疼,要完成提交SVN,点击同步等等一系列操作,繁琐。

构建命令命令比较长,参数多,难以记忆

产出文件多,发布麻烦每改动一个字母,发布的时候就会生成一个新的文件,发布的时候真是在文件堆里找!!

这一系列的问题如山倒,组内的开发同学已经没法愉快的开发了。


3.3 深度优化

  • 减少冲突问题进一步解决的方案还是细分模块,测试环境不进行文件合并,这样冲突的概率几乎很小,因为公共库经过2.0的调整已经基本稳定。

  • 缩短时间构建时间这么长,这样发展下去是不行的。花了一些时间研究FIS源码,发现FIS监听的是整个项目文件,每一次构建都要扫描全部文件,这样时间必然会随着文件增加而变长。然后进行深度改造,变得不那么像FIS了。 进行一次又一次优化,改变构建策略。依赖构建:当某个文件依赖另一个文件时,另一个文件才会被构建。假如a.html依赖了b.js ,在构建产出的文件就只有这两个文件,其他文件不会被构建,文件数也减少,时间大大缩短。

开发构建(单位ms )

The toss is more than front-end engineering and performance optimization

发布构建(单位ms)

The toss is more than front-end engineering and performance optimization

The toss is more than front-end engineering and performance optimization

构建命令优化输入命令麻烦,就用GUI界面,点点按钮就行。这里要感谢@koppthe@kolawang同学短时间内用node写的GUI。

The toss is more than front-end engineering and performance optimization

产出文件多依赖构建之后,只会产出相关文件,产出文件大大减少,发布难度减少很多。

ARS流程修复bug的时候不用ARS同步,监听文件变化直接同步到测试环境。

只需要8ms!!!。如果打开了同步按钮,修改的文件会立马上传到测试环境上,会不会有相互覆盖的问题。组内每个人负责的模块都不同,而且公共模块已经基本稳定,很难出现这样的问题,在实践中很少发生这样的事情,相反小伙伴觉得简直获得解脱,相比找文件传文件这样繁琐的流程,这轻松了许多。

发布优化构建工具会产出文件列表,点击就能打开文件夹,找到对应文件;列表对应SVN路径,直接贴到ARS就能提单。

雪碧图的优化发布的时候所有引用的CSS文件会合并成一个,然后将引用的图标合并为雪碧图,有点粗暴。因为公共的CSS文件的图片单独合并为雪碧图会更加合理,公共的图片变动频率不会那么高。开发一插件,在CSS合并前雪碧图一次,合并后再雪碧图一次。


统计与优化

用户网络类型(粗略)

The toss is more than front-end engineering and performance optimization

unknown是无法统计到的,理论上wifi还是占大部分。从其他四种类型看,wifi占据绝大部分,2g用户非常少。

PC VS Mobile

The toss is more than front-end engineering and performance optimization

在JS下载和执行效率上,移动端明显要低于PC端。

JS优化

之前APP内部的JS文件都是通过seajs来下载文件,后来发觉何不直接干脆点直接写<script>下载就好了,优化后下载执行时间下降显著:

注:这里统计的时间,包括了下载JS和执行JS的时间。

JS内嵌与外联对比

在考虑优化的时候,我们一种方案便是将外联的JS代码(仅业务代码)通过工具内嵌到页面。现在来对比下性能: http://gqq.gtimg.com/static/mobile/js/v3/page/gift/list/inappand.a9a524eb.lc.js文件大小8.7kb,gzip压缩后3.3kb。 内联加载时间几乎为0.0015793,外联的下载时间:

The toss is more than front-end engineering and performance optimization

The toss is more than front-end engineering and performance optimization

下载时间不到200ms,但相对来说已经是很长了,才8.7kb。

我们知道,DOMContentLoaded事件的触发基本意味着页面已经渲染完成,JS已经执行(异步的除外),已经达到可交互的状态了,具体可参考这篇文章。下面看下内联与外联对DOMContentLoaded的影响:

The toss is more than front-end engineering and performance optimization

蓝色线条是外联的JS,时间明显要比内联的高出一些,大概200ms。由此可见,将小量的JS文件内联到页面,能够提高速度。但大的JS文件适不适合内联,目前还没有实验。这里需要在减少HTTP请求和利用缓存之间把握一个平衡,很多时候优化准则是并不是那么容易实施,因为可能自相矛盾,也可能和工程本身相矛盾。优化不是按照准则照本宣科的做,需要灵活变通。

优化措施按照雅虎优化的14条准则,把还没做到的都处理了。

  • 脚本域名切换,去cookie。

  • 文件合并

  • 利用浏览器缓存,无限增大缓存期max-age=15552000

  • 雪碧图

  • 减少HTTP请求,构建工具内嵌JS到HTML

感觉速度还是不够快,再充分利用本地缓存和APP提供的缓存能力

  • 浏览器使用localstorage缓存脚本

  • APP缓存hash文件名脚本

  • 缓存HTML片段

调试、测试、体验流程

反向代理+白名单控制策略,域名对外访问是403,公司内网可访问。不用代理,手机直接连接wifi访问。环境分为开发——测试——预发布——正式(每个环境对应一个独立域名),任何角色(开发、测试、设计、产品)都可随时访问。

APP的debug包,可任意切换上面四种环境进行调试、测试、体验。

The toss is more than front-end engineering and performance optimization


总结

This is a summary of the work of the past year, and I have not calmed down and sorted it out. Looking back, I wonder if I made this process more complicated. There may be a process from simple to complex to simple. Persevering in optimization has never stopped. As long as it can become a little better, it will try. The so-called life is endless and endless toss.


Guess you like

Origin blog.51cto.com/14895198/2542854