导语 : 从事前端有6年+的时间了,从最开始的美工到重构再到偏向js逻辑开发的前端开发,一直在前端这个行业里面摸索和学习,我现在将自己这些年的一个心得体会来个系统性的梳理写成一篇关于性能优化的主题文章,希望对大家有点帮助,也欢迎大家提出各种意见和建议。
前端工程师是一个最近这5-6年才开始慢慢被互联网公司重视起来的一个职业,可以说是一个新兴行业,我用一张简单的思维导图带大家回顾一下前端技术发展的历程以及未来一个展望:
1.0时代没什么说的,html、css打天下的时代,那个时候你会用js开发个计算器就牛逼到不行。2.0时代是最好的时代,新技术、新思想蓬勃发展,堪称前端的工业革命,前端人员的地位得到了充分认可,门槛也有一定的提升。前端性能优化的涉及点从服务器到协议再到宿主环境本身都要有比较深刻的认识,业界目前主要还是以雅虎总结出来35条前端性能优化的黄金军规(http://www.cnblogs.com/siqi/p/3655436.html) 为参考。今天我想将这些年对前端的性能优化的经验思考整体来个串烧,带大家鸟瞰一下前端性能优化目前的一些通行做法以及这么做的出发点。文章初衷主要是对一些性能优化基础知识回顾和体系梳理,不对具体技术点做深入分析,点到为止,个人理解不对的地方欢迎各位大神拍砖,抛砖引玉。
引入话题前我还是先从一个老生常谈的话题开始:
“从用户输入URl到页面展示给用户浏览器客户端的过程中发生了什么?”
这里用个图表简单描述一下几个步骤:
web优化的目标就是如何让用户更快、更简单易用、更流畅的使用我们的服务,对于前端开发而言就是如何让我们的资源体量更小、数量更精简、内容更早呈现、交互更加人性化。
web性能优化有个大家比较公认的二八原则,就是资源从服务器处理完下发到客户端的浏览器上(上图第6步)所占的时间比例大概是整个过程的20%,也就是说服务器端可以优化的空间的效率提升并不会很明显,前端性能优化成为web性能优化重点考虑的领域,我下面将会从以下几个维度去做了自己的一个思考(跟35条军规有一定重叠)和总结:
浏览器是一个单线程解析模式去解析渲染从服务器端拿到的html文本,css加载的过程中会对后续的脚本资源加载造成阻塞,脚本的加载也会阻塞后续DOM结构的解析造成页面的留白时间增长,雅虎的35条军规中有一条就是样式文件放在头部,脚本文件放在DOM节点最末尾,减少阻塞。这里还有几个针对脚本文件的优化:
浏览器的事件模型的冒泡的特性(浏览器事件模型不清楚的自行搜索了解)我觉得是最牛逼的设计之一,解决了浏览器因为解析DOM模型不同步导致开发者往DOM对象注册事件回调找不到对象的问题。
浏览器事件注册有3个级别定义,DOM 0级事件注册(利用DOM元素行内事件属性onclick注册事件回调),DOM 1级事件注册(利用DOM元素对象的onclick API 在外部注册事件回调),DOM 2级事件注册(利用利用DOM元素对象的addEventListner/attachEvent API 在外部注册事件回调)。这里性能优化的建议就是利用DOM2级在目标DOM的父标签(大部分框架是在body标签统一注册事件监听)注册回调,收拢事件监听入口同时节约了DOM节点引用开销。
Cookie是前端作为前后台登录态校验最通常用的缓存方案,但鉴于浏览器在每次都会往同域的任何资源的http请求中自动带上cookie信息的情况,这里有必要进行优化一下,因为像css、js、image这些资源请求是不需要cookie信息的,会无端造成请求带宽的浪费(想象一下我们的cookie大小假设为10K,100个请求就是近1M的大小,高并发下以我们现行网络带宽也是蛮大的一笔负担了)。Cookie free性能优化方案的处理方式是CDN异域静态资源服务器部署我们的前端css、js、image资源。
以自己目前负责的中国香港跨境汇款为例
页面路径下的资源的请求:
CDN资源加载的请求:
通过对比CDN分开部署的资源请求并没有带上cookie信息。
浏览器针对domain,而非页面page做并发连接限制的特性,domain hash的技术优化方案的处理方式是将资源划分域分开部署,但因为过多的域划分会增加多余的DNS开销,这里通行的数量是3个以内。目前我们的港菲汇款业务只有两个域名分开部署,一个主站,一个CDN,我个人建议可以将CDN中的图片资源再单独再分一个域名部署会更好些,为什么单独把图片抽出来,后面会讲到。
针对一些界面渲染过程比较耗时的情况下,可以利用CSS3属性开启GPU来加速渲染我们的DOM,开启很简单一般我是用-webkit-transform:translateZ(0)假3D属性来唤起系统GPU加速渲染功能,关于为什么会这样,我这里做个简单的解释:
对于我们的浏览器而言,拿到我们的html文本串开始按顺序解析成DOM树,并与同步解析出来的CSS匹配生成渲染树(跟DOM树的节点不是一一对应,比如display:none的节点就不会插入渲染树)
图片来源 https://segmentfault.com/a/1190000008650975
浏览器将渲染树的节点用一个图层表示,这样层层叠加在一起生成layout,有点像ps的图层叠加的概念(可以通过火狐浏览器开发者工具3维展示更直观),一般情况下对节点的任何涉及尺寸的改变都会引起layout的重排重绘(重排和重绘是造成浏览器渲染的最大性能损耗的因素),但有种开小灶的情况Composite Layers(复合图层)直接交给我们GPU中单独的合成器进程处理,自身变化不会引起其他层的位置变化,不会引起重排重绘。tranform 3d属性是可以悄悄的告诉我们的浏览器把元素解析作为复合图层交给单独进程去处理的。
注:这里有个原则,不能滥用我们的加速,因为过多开启硬件加速会消耗更多的用户内存空间,也会比较耗电,一般针对css3动画建议开启
a、通行解决方案
图片展示前:
图片展示后:
b、缓存机制
1、给需要做离线缓存的页面html标签设定manifest属性,指定缓存的配置文件 cache.appcahe(可以设定任何扩展名,只要在服务器端配置mime-type为text/cache-manifest就行)。
2、创建上一步指定的cache.appcache配置文件,按以下截图说明来配置资源
3、在服务器端配置配置文件的扩展名映射的mime-type为text/cache-manifest
appcache离线方案诟病太多,目前接入的不多,有种慢慢变弃儿的趋势,这里提出来让大家权衡
Gzip压缩后:
b、页面切片预加载方案
性能优化静态资源维度最后一块内容就是针对页面,如何尽早输出页面模块,减少留白时间是一个思考点。facebook应用的BigPipe方案是个很不错的借鉴思想,还有淘宝也有首页做了相应的切片方案,对页面合理的分块,在服务器和客户端建立某种对应机制,让各个页面块并行的在服务器端拼接完成并吐出来,目前我对这块没有太深的了解,这里只是提出bigPipe的方案供大家参考。
TCP连接中的3次握手、慢启动的一些特性注定了连接通道的利用效率成为制约性能的一个很大的因素。因为http是基于TCP的应用协议,TCP层维度考虑还得从http几个版本的发展历史来看:
谷歌(叒是谷歌,牛逼)率先在09年基于TCP开发出全新SPDY应用协议,解决了多路复用请求优化、服务器推送的痛点问题,也为后面http2.0的推出奠定了基础。
我们可以做的优化:减少一些不必要的请求(扫除404死连接、304请求用我们的长缓存机制)去优化,尽量减少一些不必要的连接请求数。
鉴于js语言本身的灵活性,以及每个人的开发习惯,很难有很好的一个方式去验证开发者的代码实现的效率(目前更多的是用打点测速的方式去监控代码的执行时间),更多的是一种建议,大家有更好的建议可以提出来分享。
实例功能需要:实现输入框每4个字符一个空格隔开的效果
低效实现方式,用for循环:
改进后的方式:
性能优化一般都是从技术角度去入手,但我们的目标之一“让用户简单易用”也是性能优化的一环。当技术性能缺陷难于避免的时候,作为前端交互实现的执行者,更应该配合产品和交互设计师提出一个我们认为更好的交互逻辑体验方案去让我们的数据加载不那么让用户有等待的感知,让我们的提示更加的人性舒服。(交互设计师更加专业,我这里不敢班门弄斧)
文章最后对Web3.0时代做个自己的猜想,web3.0目前在业内还没有很明确定义,大家可以大胆猜想前端行业未来形态。我在这先YY一下,人工智能、大数据广泛应用应该会成为推动前端进入3.0的时代的最好契机,以此引发的前端新的革命:
结语:刚来鹅厂不久,作为前端攻城狮进入到国内顶尖互联网公司感到骄傲,性能优化是一个永恒的话题,每个阶段都有聊不完的性能优化的话题,我将我这些年的一些不成文的理解整理了一下,希望对大家有点帮助。第一次发文章,有错误的地方请大家指点一二。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。