前端优化总结贴

之前做过一个前端性能优化的项目,想想还是有不少东西可以总结下。其实从原理上说,主要是关于浏览器渲染页面的过程,因为这个过程直接决定可能优化的方式。

整体来说,在这个项目里面主要做了两方面的优化:

  • 页面加载速度的优化
  • 动画效果流畅无卡顿

现在去搜索前端性能优化,绝大部分讲的都是第一个部分,就是如何提高初次加载速度。而关于第二个部分讲到其实不多,所以还是有一些价值的。

页面加载速度的优化

首先是浏览器的关键渲染路径(CRP),它的过程是下面这样,这个部分的资料很多了,就不需要太多的分析了。

1

基于这个CRP路径,对于页面加载速度的优化方法可以分为下面这三大类:

2

  1. 减少请求资源的大小:压缩图片(这是最大头,占比重很高,之前看过一篇文章说,如果只能优化一个点应该优化哪个,结果所有专家给出的答案都是简单粗暴的图片压缩),最小化JS,HTML,CSS文件,利用缓存资源。
  2. 减少阻塞渲染的资源:阻塞渲染的话,指的就是CSS样式文件了,处理的方式有,为link标签添加媒体查询的条件,这样初次加载页面的时候,避免请求不必要的资源。还有一个大招是:在style标签里直接写内联样式,这招确实很有效。
  3. 减少阻塞解析的资源:阻塞解析的话,指的就是JS文件了,处理的方式有,用async和defer两个属性对JS脚本进行异步和后台加载。

动画效果流畅无卡顿

在每一帧里面,浏览器都要完成下面这些任务,所谓的像素管道:

3

有时候页面的卡顿可能并不明显,所以需要用分析工具来进行解析,比如chrome浏览器自带的timeline功能。Timeline的分析功能非常的强大,甚至可以直接定位到导致性能问题的JS脚本的具体行数上。

在我做的那个实际的case里面,主要优化了两个地方:一个是在滑动滚动条的时候会伴随着一些动画,这些动画不是非常流畅;另一个是,页面上的一些图片阵列是可以调整大小的,这个size变化的过程也可以更加的流畅。具体的细节记录在了github的项目里面。

这两个点其实本质上都是一个问题,这个问题也是最经常出现的,称为forced synchronous Layout,简称为FSL,timeline工具会给出非常明显的提示。

导致FSL的原因是:在for循环里先对DOM元素的几何尺寸相关属性进行了获取操作,然后又尝试去修改这些DOM元素的style。从上面那个像素管道图上看的话,相当于在style之前先进行了layout,然后又再进行style和layout,这个就是FSL。

解决的办法是,把几何尺寸相关属性的读取放到for循环之外,放到一个变量里。

下面这个篇文章给出了会触发layout的DOM属性和方法:

http://gent.ilcore.com/2011/03/how-not-to-trigger-layout-in-webkit.html

Angular:$parse一个高阶的方法

感觉angular已经学到家了吗?No no no,马上来个高级的用法:$parse

如果你想在AngularJS的知识海洋里取得更深层次的突破,$parse是一个你必须要知道的服务,它几乎用在了所有的指令上,学习了它据说可以让你脑洞大开。

所以$parse到底是个什么鬼?让俺们从已经知道的ngClick开始。ngClick指令,会接收一个表达式,然后当这个指令元素被点击的时候,去执行这个表达式,那末它的内部机制是怎样的呢?恭喜你,猜对了,就是$parse

$parse会把接收的表达式转化为一个函数并返回。而之后当你调用这个函数的时候,会给这个函数传入一个参数,这个参数就是这个表达式运行的context。所以返回一个函数只是一个形式,关键是允许你可以在某个context下执行某些表达式。。。

It will execute the expression with the given context

JS的世界里,context可以是一个复杂的概念,但是对于$parse的使用来说,我们可以简单的把它理解为一个JS对象。表达式里的所有东西都要在这个JS对象上运行。

比如下面这个例子:

1

在上面这个例子里,我们可以在一个context环境里安全的去解析某个字符串的值。

利用这个功能,我们可以写一个简化版的myClick,像下面这样:

2

在这个case里,指令的域成了context

上面这个简化的ngClick指令比真正的ngClick还是有差别的,因为真正的ngClick允许向生成的函数中传入$event对象。这是怎么实现的呢?原来$parse返回的函数还能接收第二个参数,当作附加的context

而在click的回调函数中,我们恰好能得到event对象,这样我们就能把它传入了:

3

链接:https://blog.umur.io/2014/02/25/advanced-angular-parse/