参考: https://www.cnblogs.com/wemzhugo/p/3345987.html
参考: https://www.jianshu.com/p/2c05e0a6a0a1
一、资源压缩与合并
主要包括这些方面:html压缩、css 压缩、js的压缩和混乱和文件合并。
资源压缩可以从文件中去掉多余的字符,比如回车、空格。你在编辑器中写代码的时候,会使用缩进和注释,这些方法无疑会让你的代码简洁而且易读,但它们也会在文档中添加多余的字节。
减少HTTP请求数。
- 合并JS文件和CSS文件。
- 合并框架图片及相对变动较少的图片或成一张,通过CSS背景切割来完成渲染。
- 合理使用本地Cache来缓存JS/CSS/IMAGE。
减小被请求文件的大小,减少请求数据占用的网络带宽。
- 压缩JS体积:删除JS中空白换行、注释、混淆,把长变量换成短变量。
- 压缩CSS体积:删除CSS注释、写法尽量用简写。
- 使用(X)HTML+CSS方式搭建网站结构,提供CSS重用性,来减少(X)HTML文件大小。
- 使用服务器端GZIP压缩JS/CSS文件,缩小传输文件大小。
删除页面中一些可有可无的内容。
主要指冗余的空格、制表符、空白行、双引号、单引号、注释等。
删除网页代码中的空语句。
例如:
<span style='font-family:宋体'>你好<span lang=EN-US><o:p></o:p></span></span>
很明显,在“你好”后边的那些语句是没有任何作用的,我们可以把它删掉。
删除HTML的默认属性。
HTML语言有很多默认属性,比如对齐、字体、颜色等,但网页制作软件会加入这些无用的代码。如:align属性默认是左对齐,所以在左对齐时我们没必要再写“align=left”。
优化CSS。
例如:使用简写的CSS。
又或者:
<p class="decorated">1</p>
<p class="decorated">2</p>
<p class="decorated">3</p>
<p class="decorated">4</p>
可以用div来包含:
<div class="decorated">
<p>1</p>
<p>2</p>
<p>3</p>
<p>4</p>
</div>
Visibility快于Display。
visibility:隐藏对应的元素但不挤占该元素原来的空间。
display:隐藏对应的元素并且挤占该元素原来的空间。
CSS
display:none,HTML元素(对象)的宽度、高度等各种属性值都将“丢失”,视为不存在,且不加载;
visibility:hidden,HTML元素(对象)仅仅是在视觉上看不见(完全透明),而它所占据的空间位置仍然存在,具有高度、宽度等属性值,在浏览时保留位置。
Overflow属性值{visible|hidden|scroll|auto}前提是先要限制DIV的宽度(width)和高度(height)。二者都是隐藏HTML元素,在视觉效果上没有区别,但在一些DOM操作中二者还是有所不同的。
保持同一URL的大小写一致性。
Internet Explorer的缓冲区也是区别对待大小写字符串的。因此,作为Web开发者,一定要记住保持相同链接的URL字符串在不同位置的大小写的一致性。否则,就会在浏览器的缓冲区中存放同一位置的不同文件备份,也增加了下载同一位置内容的请求次数。
让标记有始有终。
不要将整个页面内容塞到一个Table中。
因为Table要等里面的所有内容都加在完毕后才显示出来,如果某些内容无法访问,则会拖延整个页面的访问速度。正确的做法是,将内容分割到几个具有相同格局的Table中去,不要全都塞到一个Table里。
使用iframe嵌套另一个页面。
如果需要插入广告代码,又不想影响速度,那么使用iframe最合适不过了。不会因为广告代码延迟而影响页面的显示。
把js文件移到HTMl文件末尾,css文件移到顶端。
因为JavaScript在处理的过程中会阻塞后面的页面显示,并且也会使HTML请求被阻止。
CSS 放到最顶部,浏览器能够有针对性的对 HTML 页面从顶到下进行解析和渲染。
友情链接的学问。
- 只做文字链接,做文字链接是不会延迟网页速度的。
- 将所有链接放到一个独立的分页中区,然后在首页链接上该页。
- 如果友情链接一定要出现在首页,那么请将链接所在的整个Table放到页面的最下方,因为页面是由上到下逐行显示的。
- 友情链接的Logo图片先下载后再上传到自己的网页空间。
图片优化。
- 减少图片数:去除不必要的图片。
- 降低图像质量:JPG格式的图片,降低5%的图片看起来变化不是很大,但文件大小变化很明显。
- 使用恰当的格式:JPG一般用于展示风景、人物、艺术照的摄影作品,有时也用在电脑截屏上;GIF提供的颜色较少,可用在一些对颜色要求不高的地方,如网站Logo、按钮、表情等;PNG格式能提供透明背景,一般用于需要背景透明显示或对图像质量要求较高的网页上。
网址后加斜杠。
标明高度和宽度。
如果没有设置,则浏览器一边下载图片一边计算大小,如果图片很多,则浏览器就需要不断地调整页面,这不但影响速度,也影响浏览体验。当浏览器知道了高度和宽度后,即使图片无法显示,页面上也会腾出图片的空位,然后继续加载后面的内容。从而加载快了,浏览体验也更好了。
1.html压缩
html代码压缩就是压缩这些在文本文件中有意义,但是在HTML中不显示的字符,包括空格,制表符,换行符等,还有一些其他意义的字符,如HTML注释也可以被压缩。
如何进行html压缩:
- 使用在线网站进行压缩(开发过程中一般不用)
- nodejs 提供了html-minifier工具
- 后端模板引擎渲染压缩
如何进行html压缩:
- 使用在线网站进行压缩(开发过程中一般不用)
- nodejs 提供了html-minifier工具
- 后端模板引擎渲染压缩
2.css代码压缩
css代码压缩简单来说就是无效代码删除和css语义合并。
如何进行css压缩:
- 使用在线网站进行压缩(开发过程中一般不用)
- 使用html-minifier工具
- 使用clean-css对css压缩
3.js的压缩和混乱
js的压缩和混乱主要包括以下这几部分:
- 无效字符的删除
- 剔除注释
- 代码语义的缩减和优化
- 代码保护(代码逻辑变得混乱,降低代码的可读性,这点很重要)
如何进行js的压缩和混乱
- 使用在线网站进行压缩(开发过程中一般不用)
- 使用html-minifier工具
- 使用uglifyjs2对js进行压缩
其实css压缩与js的压缩和混乱比html压缩收益要大得多,同时css代码和js代码比html代码多得多,通过css压缩和js压缩带来流量的减少,会非常明显。所以对大公司来说,html压缩可有可无,但css压缩与js的压缩和混乱必须要有!
文件与文件之间有插入的上行请求,增加了N-1个网络延迟
受丢包问题影响更严重
keep-alive方式可能会出现状况,经过代理服务器时可能会被断开,也就是说不能一直保持keep-alive的状态
压缩合并css和js可以减少网站http请求的次数,但合并文件可能会带来问题:首屏渲染和缓存失效问题。那该如何处理这问题呢?----公共库合并和不同页面的合并。
如何进行文件合并
- 使用在线网站进行文件合并
- 使用nodejs实现文件合并(gulp、fis3)
二、非核心代码异步加载异步加载的方式
1. 异步加载的方式
异步加载的三种方式——async和defer、动态脚本创建。
1. async方式
async属性是HTML5新增属性,需要Chrome、FireFox、IE9+浏览器支持
async属性规定一旦脚本可用,则会异步执行
async属性仅适用于外部脚本
如果是多个脚本,该方法不能保证脚本按顺序执行
<script type="text/javascript" src="xxx.js" async="async"></script>
2. defer方式
兼容所有浏览器
defer属性规定是否对脚本执行进行延迟,直到页面加载为止
如果是多个脚本,该方法可以确保所有设置了defer属性的脚本按顺序执行
如果脚本不会改变文档的内容,可将defer属性加入到script标签中,以便加快处理文档的速度
3. 动态创建script标签
在还没定义defer和async前,异步加载的方式是动态创建script,通过window.onload方法确保页面加载完毕再将script标签插入到DOM中,具体代码如下:
function addScriptTag(src){
var script = document.createElement('script');
script.setAttribute("type","text/javascript");
script.src = src;
document.body.appendChild(script);
}
window.onload = function(){
addScriptTag("js/index.js");
}
2. 异步加载的区别
- defer是在HTML解析完之后才会执行,如果是多个,按照加载的顺序依次执行
- async是在加载完之后立即执行,如果是多个,执行顺序和加载顺序无关
三、利用浏览器缓存
对于web应用来说,缓存是提升页面性能同时减少服务器压力的利器。
浏览器缓存类型
通过版本化控制客户端缓存
如何及时更新这些被缓存的文件呢?通过一个简单的配置,通过修改JS的版本来及时告诉浏览器,这些文件必须重新请求了,不要继续使用浏览器缓存中的数据了。方案有以下几个:
- 手动改这些JS的文件名。
- 手动改这些JS的路径。
- 通过URL Rewrite方式来重定位JS路径。
- 通过一个在高响应服务器上的JS配置告知页面,这个页面该链接哪些JS文件。
- 大版本不变,小版本不断追加,等一定时间后统一更新,高效利用缓存。
1. 强缓存
不会向服务器发送请求,直接从缓存中读取资源,在chrome控制台的network选项中可以看到该请求返回200的状态码,并且size显示from disk cache或from memory cache;
相关的header:
Expires :response header里的过期时间,浏览器再次加载资源时,如果在这个过期时间内,则命中强缓存。它的值为一个绝对时间的GMT格式的时间字符串, 比如Expires:Thu,21 Jan 2018 23:39:02 GMT
Cache-Control :这是一个相对时间,在配置缓存的时候,以秒为单位,用数值表示。当值设为max-age=300时,则代表在这个请求正确返回时间(浏览器也会记录下来)的5分钟内再次加载资源,就会命中强缓存。比如Cache-Control:max-age=300。
简单概括:其实这两者差别不大,区别就在于 Expires 是http1.0的产物,Cache-Control是http1.1的产物,两者同时存在的话,Cache-Control优先级高于Expires;在某些不支持HTTP1.1的环境下,Expires就会发挥用处。所以Expires其实是过时的产物,现阶段它的存在只是一种兼容性的写法。强缓存判断是否缓存的依据来自于是否超出某个时间或者某个时间段,而不关心服务器端文件是否已经更新,这可能会导致加载文件不是服务器端最新的内容,那我们如何获知服务器端内容较客户端是否已经发生了更新呢?此时我们需要协商缓存策略。
2. 协商缓存
向服务器发送请求,服务器会根据这个请求的request header的一些参数来判断是否命中协商缓存,如果命中,则返回304状态码并带上新的response header通知浏览器从缓存中读取资源;另外协商缓存需要与cache-control共同使用。
相关的header:
1. Last-Modified和If-Modified-Since
当第一次请求资源时,服务器将资源传递给客户端时,会将资源最后更改的时间以“Last-Modified: GMT”的形式加在实体首部上一起返回给客户端。
Last-Modified: Fri, 22 Jul 2016 01:47:00 GMT
客户端会为资源标记上该信息,下次再次请求时,会把该信息附带在请求报文中一并带给服务器去做检查,若传递的时间值与服务器上该资源最终修改时间是一致的,则说明该资源没有被修改过,直接返回304状态码,内容为空,这样就节省了传输数据量 。如果两个时间不一致,则服务器会发回该资源并返回200状态码,和第一次请求时类似。这样保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。一个304响应比一个静态资源通常小得多,这样就节省了网络带宽。
但last-modified 存在一些缺点:
Ⅰ.某些服务端不能获取精确的修改时间
Ⅱ.文件修改时间改了,但文件内容却没有变
既然根据文件修改时间来决定是否缓存尚有不足,能否可以直接根据文件内容是否修改来决定缓存策略?----ETag和If-None-Match
2. ETag和If-None-Match
Etag是上一次加载资源时,服务器返回的response header,是对该资源的一种唯一标识,只要资源有变化,Etag就会重新生成。浏览器在下一次加载资源向服务器发送请求时,会将上一次返回的Etag值放到request header里的If-None-Match里,服务器只需要比较客户端传来的If-None-Match跟自己服务器上该资源的ETag是否一致,就能很好地判断资源相对客户端而言是否被修改过了。如果服务器发现ETag匹配不上,那么直接以常规GET 200回包形式将新的资源(当然也包括了新的ETag)发给客户端;如果ETag是一致的,则直接返回304知会客户端直接使用本地缓存即可。
两者之间对比
首先在精确度上,Etag要优于Last-Modified。Last-Modified的时间单位是秒,如果某个文件在1秒内改变了多次,那么他们的Last-Modified其实并没有体现出来修改,但是Etag每次都会改变确保了精度;如果是负载均衡的服务器,各个服务器生成的Last-Modified也有可能不一致。
第二在性能上,Etag要逊于Last-Modified,毕竟Last-Modified只需要记录时间,而Etag需要服务器通过算法来计算出一个hash值。
第三在优先级上,服务器校验优先考虑Etag
缓存的机制
强制缓存优先于协商缓存进行,若强制缓存(Expires和Cache-Control)生效则直接使用缓存,若不生效则进行协商缓存(Last-Modified / If-Modified-Since和Etag / If-None-Match),协商缓存由服务器决定是否使用缓存,若协商缓存失效,那么代表该请求的缓存失效,重新获取请求结果,再存入浏览器缓存中;生效则返回304,继续使用缓存。
用户行为对浏览器缓存的影响
- 地址栏访问,链接跳转是正常用户行为,将会触发浏览器缓存机制;
- F5刷新,浏览器会设置max-age=0,跳过强缓存判断,会进行协商缓存判断;
- ctrl+F5刷新,跳过强缓存和协商缓存,直接从服务器拉取资源。
四、使用CDN
大型Web应用对速度的追求并没有止步于仅仅利用浏览器缓存,因为浏览器缓存始终只是为了提升二次访问的速度,对于首次访问的加速,我们需要从网络层面进行优化,最常见的手段就是CDN(Content Delivery Network,内容分发网络)加速。通过将静态资源(例如javascript,css,图片等等)缓存到离用户很近的相同网络运营商的CDN节点上,不但能提升用户的访问速度,还能节省服务器的带宽消耗,降低负载。
CDN是怎么做到加速的呢?
其实这是CDN服务商在全国各个省份部署计算节点,CDN加速将网站的内容缓存在网络边缘,不同地区的用户就会访问到离自己最近的相同网络线路上的CDN节点,当请求达到CDN节点后,节点会判断自己的内容缓存是否有效,如果有效,则立即响应缓存内容给用户,从而加快响应速度。如果CDN节点的缓存失效,它会根据服务配置去我们的内容源服务器获取最新的资源响应给用户,并将内容缓存下来以便响应给后续访问的用户。因此,一个地区内只要有一个用户先加载资源,在CDN中建立了缓存,该地区的其他后续用户都能因此而受益。
五、预解析DNS
资源预加载是另一个性能优化技术,我们可以使用该技术来预先告知浏览器某些资源可能在将来会被使用到。
通过 DNS 预解析来告诉浏览器未来我们可能从某个特定的 URL 获取资源,当浏览器真正使用到该域中的某个资源时就可以尽快地完成 DNS 解析。例如,我们将来可从 example.com 获取图片或音频资源,那么可以在文档顶部的 标签中加入以下内容:
<link rel="dns-prefetch" href="//example.com">
当我们从该 URL 请求一个资源时,就不再需要等待 DNS 的解析过程。该技术对使用第三方资源特别有用。通过简单的一行代码就可以告知那些兼容的浏览器进行 DNS 预解析,这意味着当浏览器真正请求该域中的某个资源时,DNS 的解析就已经完成了,从而节省了宝贵的时间。
另外需要注意的是,浏览器会对a标签的href自动启用DNS Prefetching,所以a标签里包含的域名不需要在head中手动设置link。但是在HTTPS下不起作用,需要meta来强制开启功能。这个限制的原因是防止窃听者根据DNS Prefetching推断显示在HTTPS页面中超链接的主机名。下面这句话作用是强制打开a标签域名解析
<meta http-equiv="x-dns-prefetch-control" content="on">