前端常用性能优化详解
一、减少HTTP请求
每个请求都是有成本的,既包含时间成本也包含资源成本。一个完整的请求都需要经过 DNS寻址、与服务器建立连接、发送数据、等待服务器响应、接收数据这样一个 “漫长” 而复杂的过程。时间成本就是用户需要看到或者 “感受” 到这个资源是必须要等待这个过程结束的,资源上由于每个请求都需要携带数据,因此每个请求都需要占用带宽。
另外,由于浏览器进行并发请求的请求数是有上限的 ,因此请求数多了以后,浏览器需要分批进行请求,因此会增加用户的等待时间,会给用户造成站点速度慢这样一个印象,。
常用的具体操作方法有:资源的压缩与合并,CSS Sprites等
二、非核心代码异步加载
1、异步加载方式
- (1) 动态脚本加载
如下代码:
var myScript= document.createElement("script");
myScript.type = "text/javascript";
myScript.src="a.js";
document.body.appendChild(myScript);
- (2) defer
- (3) async
2、defer和async的区别
- (1)defer是在HTML解析完之后才会执行,如果是多个,按照加载顺序依次执行。
- (2) async是在加载完之后立即执行,如果是多个,执行顺序和加载顺序无关
三、利用浏览器的缓存
浏览器缓存是提高性能最重要的一步!
获取资源形式 | 状态码 | 发送请求到服务器 | |
---|---|---|---|
强缓存 | right-aligned | 200(from cache) | 否,直接从缓存取 |
协议缓存 | centered | 304(not modified) | 是,通过服务器来告知缓存是否可用 |
1、强缓存(本地缓存)
强缓存相关的header字段:
- ① Expires(过期时间)
例子:Expires: Thu, 21 Jan 2018 23:59:59 GMT(绝对时间)
浏览器可能和服务器时间不一致,比对的时候浏览器时间为主,下发则以服务器时间为主。在这个时间范围内都是从浏览器拿缓存。 - ② Cache-Control
例子:Cache-Control: max-age=3600(相对时间)
指拿到资源后3600秒内不会再请求服务器,在这个时间内都可以从浏览器拿缓存。
如果同时设置了Cache-Control响应首部字段的max-age,则Expires会被忽略。
2、协商缓存
协商缓存相关的header字段:
-
① Last-Modified / If-Modified-Since
例子:Last-Modified: Wed, 26 Jan 2018 00:59:59 GMT -
浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在respone的header加上Last-Modified的header,这个header表示这个资源在服务器上的最后修改时间
-
浏览器再次跟服务器请求这个资源时,在request的header上加上If-Modified-Since的header,这个header的值就是上一次请求时返回的Last-Modified的值
-
服务器再次收到资源请求时,根据浏览器传过来If-Modified-Since和资源在服务器上的最后修改时间判断资源是否有变化,如果没有变化则返回304 Not Modified,但是不会返回资源内容;如果有变化,就正常返回资源内容。当服务器返回304 Not Modified的响应时,response header中不会再添加Last-Modified的header,因为既然资源没有变化,那么Last-Modified也就不会改变,这是服务器返回304时的response header
-
浏览器收到304的响应后,就会从缓存中加载资源
-
如果协商缓存没有命中,浏览器直接从服务器加载资源时,Last-Modified的Header在重新加载的时候会被更新,下次请求时,If-Modified-Since会启用上次返回的Last-Modified值
-
② Etag / If-None-Match
这两个值是由服务器生成的每个资源的唯一标识字符串,只要资源有变化就这个值就会改变;其判断过程与Last-Modified/If-Modified-Since类似,与Last-Modified不一样的是,当服务器返回304 Not Modified的响应时,由于ETag重新生成过,response header中还会把这个ETag返回,即使这个ETag跟之前的没有变化。
服务器返回资源的时候会返回一个Etag值,当过了强缓存的时间,浏览器再去向服务器请求资源,HTTP会加一个key值即If-None-Match,和value值即Etag即 If-None-Match: Etag
。
通过在Nginx里server配置中设置加上etag on
来开启etag。
Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。
额外:
为什么既生Last-Modified何生Etag?
你可能会觉得使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要Etag呢?HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:
-
一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;
-
某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断;
四、使用CDN
CDN:内容分发网络(Content delivery network或Content distribution network)是指一种通过互联网互相连接的电脑网络系统,利用最靠近每位用户的服务器,更快、更可靠地将音乐、图片、视频、应用程序及其他文件发送给用户,来提供高性能、可扩展性及低成本的网络内容传递给用户。
举个栗子:
以前还没有火车票代售点,12306.cn也只不过是最近几年才有。那时候火车票还智能在火车站的售票大厅购买,好多小县城不通火车,火车票要到市里去买,从小县城到市里去买火车票来回要花不少时间。
后来小县城有了火车票代售点,可以直接在代售点购买车票,方便了很多,全市人民再也不用苦逼的排队在一个点买票了,可以分散到不同的火车票代售点。那么CDN就可以理解为分布在每个县城的火车票代售点,用户在浏览网站时,CDN会选择一个离用户最近的CDN边缘节点来响应用户的请求,这样上海的移动用户的请求就不用千里迢迢跑到北京电信机房的服务器上了(假设源站部署在北京电信机房)。
这样,CDN节点解决了跨运营商和跨地域访问的问题,访问时间大大降低,同时,大部分请求在CDN边缘节点完成,CDN起到了分流作用,减轻了源站的负载。
五、预解析DNS
-
(1) <meta http-equiv="x-dns-prefetch-control" content="on">
页面中的<a>标签在高级浏览器中是默认打开了DNS预解析的,但是,如果网站是https协议的,很多浏览器是关闭DNS预解析的,那么通过上面的设置,可以打开DNS预解析。 -
(2) <link rel="dns-prefetch" href="//host_name_to_prefetch.com">