1

等待时间

前端性能,个人理解为在用户输入URL或者点击链接之后,直到网页完全展现所需要的时间,本文暂时定义为等待时间。

那么前端性能优化就是要缩短这个等待时间。

定义问题

等待时间没有满足用户预期。

明确目标

缩短等待时间,达到用户预期或者技术预期。

分析问题

都知道有钱可以为所欲为,那么也可以买配置更高的电脑,速度更快的宽带,性能更好的服务器,接下来的讨论都受到贫穷的限制,无法负担得起昂贵的费用,这是一个前提(背景)。

从输入 URL 到页面加载完成,发生了什么?

1972344434-5cdb8424786ae_articlex.png

分解问题

由流程可知,等待时间时间主要由网络请求页面渲染这两大方面构成。

  • 建立连接,传输请求,传输响应都归纳到网络请求;众所周知,网络一直是计算机系统的性能瓶颈之一
  • 页面渲染有很多性能浪费可以避免,需要足够重视。
  • 发起请求,接收响应耗费时间很少,优化空间很小,可以忽略。
  • 响应请求,构建响应是后端性能优化的重点,可以忽略。

寻找方式

明确目的,分解问题之后,现在是要缩短网络请求时间和页面渲染时间。

由物理可知,时间=总量/速率,想要缩短时间,可以提高速率或者减少总量。

流程中,有些步骤是可以优化的,可以减少中间的某些步骤消耗的时间。

寻找方法

老许,你要性能不要,只要你开金口,我马上就给你想办法

不搞这些虚的了,首先从常用技术入手,由于常用技术总是变化(吐槽一下,前端技术更新比我的亚索都快),所以就找到他们的祖宗,HTML,CSS,JavaScript,其实改进他们就是具体方法,更具有可操作性。

小结

在贫穷的限制下,我们将性能优化分解成了网络请求页面渲染两个方面,通过优化HTML,CSS,JavaScript的方法来达到目的

网络请求

HTTP遍布了互联网的每个角落,那么对HTTP的理解,使用,优化就很重要了。

网络请求分为HTTP和非HTTP两方面,而非HTTP又分为HTML,CSS,JavaScript。

HTTP优化

keep-alive连接,持久连接重用了TCP连接,减少了连接建立的开销,使连接保持在已谐调状态。详细参考《HTTP权威指南》 4.2.2 性能聚焦区域和4.5 持久连接

正确使用HEAD方法,可以减少传输不必要的响应主体

使用内容编码技术,可以减小资源的体积,一般使用gzip

使用范围请求首部,可以只请求资源的一部分;甚至可以并行发送范围请求,同时获取资源的不同部分,然后拼接回去

使用差异编码技术,可以只请求资源的变更部分,这一技术需要客户端和服务端支持

HTTP缓存

私有缓存一般由客户端提供给用户使用,共有代理缓存一般由公司提供给多个客户端使用。

缓存可以减少资源的传输,效果取决于命中率,一般有文档命中率,更精确的有字节命中率

强制缓存
对比 Expires ?Cache-Control
用法 Expires: <date> Cache-Control: max-age=<s>
说明 date是GMT,在date之前可以使用缓存 s是数字,单位是秒,在s秒内可以使用缓存
注意 使用绝对时间,时钟不同步会导致问题 -
优先级
协商缓存

标识为no-cache的响应实际上是可以缓存的,只是再验证成功之后才允许使用缓存;如果再校验失败,需要缓存返回的新资源

首部 版本 备注
Pragma: no-cache HTTP/1.0+ 虽然不推荐使用,但是加上可以兼容HTTP/1.0+
?Cache-Control: no-cache HTTP/1.1
首部 备注
If-Modified-Since: <date> 需要Last-Modified: <date>配合
If-None-Match: <tags> 需要ETag: <tags>配合
对比 Last-Modified ETag
响应 Last-Modified: <date> ETag: <tags>
请求 If-Modified-Since: <date> If-None-Match: <tags>
说明 date是GMT,验证资源在date之后有没有被修改 tags是标识符,验证资源有没有被修改
程度 弱验证 可强可弱
注意 内容没有变化,但是date却变化了
内容变化了,但是不重要,date也变化了
date精确到秒,内容在亚秒级变化,date却没有变化
tags可以赋予多种含义,例如版本号,内容hash值等
强验证和弱验证

强验证和弱验证的区别是:能不能唯一标识资源的一个实例

ETag,本身是强验证码,也可以作为弱验证码来用,验证会匹配字符串全部
ETag,如果加了W/前缀,就是弱验证码,验证会匹配字符串部分,只要前缀匹配,无论后面的时候一样,都会通过验证
Last-Modified,就是弱验证码,由于时间只能精确到秒,而一秒内,文件可能变化了很多次,所以是弱验证码

E-tag: "3116092995",假设这个值是文件大小,那么即使没有W/前缀,它也是弱验证码

HTTP/2

请求/响应复用

服务端推送

首部压缩

参考内容

非HTTP优化

CDN

CDN(Content Delivery Network,即内容分发网络)是一种分布式缓存,不仅有缓存的优点,还有地理优势,它们通常会智能地选择与用户更近的设备提供资源。

cookie优化

同一个域名下的请求会不分青红皂白地携带 Cookie,而静态资源往往并不需要 Cookie 携带什么认证信息。把静态资源和主页面置于不同的域名下,完美地避免了不必要的 Cookie 的出现!

看起来是一个不起眼的小细节,但带来的效用却是惊人的。以电商网站静态资源的流量之庞大,如果没把这个多余的 Cookie 拿下来,不仅用户体验会大打折扣,每年因性能浪费带来的经济开销也将是一个非常恐怖的数字。

异步操作

异步可以不用等待磁盘IO,网络IO,更加有效地利用资源。

举例说明:A请求需要3s,B请求需要5s
同步需要8s,异步需要5s
同步:0s时A请求发送,3s时A请求完成,B请求发送,8s时B请求完成
异步:0s时A请求发送,B请求发送,3s时A请求完成,5s时B请求完成

同步会阻塞其他操作,异步不会阻塞其他操作,这里不再赘述。

压缩

HTML压缩,CSS压缩,JavaScript混淆,压缩,可以减小资源的体积。

这里的压缩是指删除注释,空格,回车等不必要的字符,和内容编码的压缩是两种方式。

CSS简化

CSS要尽量精简,尽量复用,不要定义过大的class
如果使用SCSS,过多使用mixin,function,会增加过多重复的CSS代码

举例说明,只是说明意思

<button class="bad-ok-button">OK</button>
<button class="bad-cancel-button">Cancel</button>

bad-ok-button {
  border:2px solid; border-radius:25px;
  background: green;
};
bad-cancel-button {
  border:2px  solid; border-radius:25px;
  background: red;
};
<button class="good-button good-button--ok">OK</button>
<button class="good-button good-button--cancel">Cancel</button>

good-button { border:2px solid; border-radius:25px; };
good-button--ok { background: green; };
good-button--cancel { background: red; };

页面渲染

就拿Chrome来说,有Google这个爸爸,其实是不需要我这样的菜鸡去担忧,操心浏览器渲染的优化,其实我所能做的最大的努力也是一句话,就是不添乱

标签位置

CSS资源放在head中,因为CSS下载完成才会构建CSSOM树,CSSOM树完成才会构建Render树。

JavaScript资源放在body底部,因为JavaScript会抢占控制权。

JavaScript引擎和Render引擎是相互独立的
因为JavaScript可能会修改DOM和CSSOM,所以JavaScript执行时候,会停止渲染,因为那是徒劳的。

预处理

dns-prefetch提前进行域名解析
pre-connect提前进行TCP连接
preload,提高资源下载优先级,表明资源是现在必要的资源
prefetch,降低资源下载优先级,表明资源是之后需要的资源

参考内容

异步操作

不经过任何处理的情况下,下载和执行都会阻塞HTML解析

async异步下载(不阻塞),加载完成后马上执行(阻塞),不一定会按照顺序执行
defer异步下载(不阻塞),在所有元素解析完成之后,DOMContentLoaded事件触发之前执行(虽然阻塞,但是首次HTML解析已经完成),会按照顺序执行。

参考内容

DOM操作

页面渲染,会经过flow和paint,而Repaint开销很大,Reflow开销更大,尽量减少触发Reflow和Repaint,或者减少开销

  1. 减少读取DOM元素的属性
  2. 将对DOM元素的多次操作合并
    将DOM元素拷贝,进行多次操作后,替换原DOM元素
    对DOM元素修改display: none,进行多次操作后,恢复显示
    对DOM元素的多次CSS属性修改,可以替换为对class修改
  3. position属性为absolutefixed的元素,重排的开销会比较小,因为不用考虑它对其他元素的影响
  4. transform做形变和位移

CSS优化

CSS要尽量简单,不要过分嵌套,不要过分使用类选择器以外的选择器

简单的CSS可以减轻渲染的压力,也更加容易修改和维护

注意:CSS选择器是从右向左进行匹配的

参考内容

BEM,CSS模块化

渐进式图片

先下载低像素的图片,既节省时间,又减小首次渲染压力;后面会下载正常像素图片,提供完美的用户体验。

按需加载

图片的按需加载,不是首屏需要的图片,在需要的时候再加载

JavaScript优化

尽量访问局部变量,尽量减少作用域链搜索,可以加快JavaScript执行,从而更快渲染页面

总结

前端性能优化.jpg

参考文章


贼他妈坏坏
14 声望0 粉丝