在面试的时候,属于高频问题。
相似问题:
- 输入一个url到页面显示发生了什么?
- .ajax的工作原理是什么?
- 性能优化的解决方案?
- 对http的了解?
- 浏览器的渲染机制是什么?
说在前面:
1.计划只是合理分配现有财产,并不能增加收入。
2.省钱也要讲大头,细节其实并不重要。
要优化一个网页,首先要梳理出一个网页从输入url到页面出现的所有流程,并在所有可优化的地方下手。
输入一个url会有以下流程:
- 浏览器单独开启一个http请求线程。
- dns域名查询,建立http连接。
- 返回html页面,浏览器渲染dom树,css规则树渲染页面。
一、优化dns域名查询时间
浏览器DNS查找顺序一般是这样的:
浏览器缓存→系统缓存→路由器缓存→ISP DNS 缓存→递归搜索。
可以利用浏览器对DNS预取:
<link rel="dns-prefetch" href="//fonts.googleapis.com">
设置dns-prefetch。
二、优化http请求次数
每一个http请求都是需要时间的,尽量减少http请求次数。
- 合并小图标,也就是平常说的雪碧图。
- 压缩和混淆js和css文件,使用一些打包和压缩工具。
- 将部分css和js写到html页面里面。淘宝网将部分的css直接写在html里面。
三、利用http缓存
1.Cache-Control 控制缓存
下面是淘宝的缓存设置,过期时长是一年。
后台设置类似于下面:
header("Content-type:text/html;charset=utf-8");
//用Cache-Control告诉浏览器有效期 5秒
header("Cache-Control:max-age=15");
2.使用响应头Expires控制缓存
//设置10秒的有效期,时间格式是GMT
//时间是当前服务器时间 + 10秒
$expires = gmdate('D, d M Y H:i:s', time() + 10) . ' GMT';
header("Expires:$expires");
淘宝网设置:
expires的弊端是有效期是以服务器时间来设置,如果客户端的时间和服务端时间有一定的时间差,缓存的控制就有问题了。
Cache-Control(支持) 和 expires 同时设置有效期,以 Cache-Control设置的有效期为准。
设置expires和cache-control都是属于强缓存,对于已经缓存,且未过期的图片,不会再发起http请求。
3.通过HTTP 304: Not Modified 使用缓存
304是协商缓存,
下面php代码实现了协商缓存:
下面是淘宝网304协商缓存:
点进来:https://www.cnblogs.com/chenqf/p/6386163.html
4.其他缓存
其他缓存为服务器端缓存,数据库缓存。如代理服务器缓存,redis缓存等。缓存规则是能用缓存,则先用缓存。
四、静态资源放到其他域名下
淘宝的静态资源请求如下:
将静态资源放到其他服务器有两点原因:
- 减轻服务器的压力,显然两台服务器更快。
- 因为跨域问题,静态请求不会携带cookie,提高了传输效率。
五、http请求长连接
http1.0默认是短连接,每发一次请求,建立一次连接。在请求很多的情况下,增加了请求时长。
使用http1.1 ,http1.1是默认长连接,HTTP 1.1还允许客户端不用等待上一次请求结果返回,就可以发出下一次请求,但服务器端必须按照接收到客户端请求的先后顺序依次回送响应结果。
或者在http1.0设置求头
Connection: keep-alive
淘宝网:
六、优先使用get请求
Get请求优于post。
post请求的过程:
- 浏览器请求tcp连接(第一次握手)
- 服务器答应进行tcp连接(第二次握手)
- 浏览器确认,并发送post请求头(第三次握手)
- 服务器返回100 continue响应
- 浏览器开始发送数据
- 服务器返回200 ok响应
get请求的过程
1. 浏览器请求tcp连接(第一次握手)
2. 服务器答应进行tcp连接(第二次握手)
3. 浏览器确认,并发送get请求头和数据(第三次握手)
4. 服务器返回200 ok响应
理论上get速度是post的1.5倍。
七、使用gzip压缩
点进来:http://web.jobbole.com/85681/
Accept-Encoding 和 Content-Encoding 是 HTTP 中用来对「采用何种编码格式传输正文」进行协定的一对头部字段。它的工作原理是这样:浏览器发送请求时,通过 Accept-Encoding 带上自己支持的内容编码格式列表;服务端从中挑选一种用来对正文进行编码,并通过 Content-Encoding 响应头指明选定的格式;浏览器拿到响应正文后,依据 Content-Encoding 进行解压。服务端也可以返回未压缩的正文,但这种情况不允许返回 Content-Encoding。这个过程就是 HTTP 的内容编码机制。
淘宝的请求:
gzip文件压缩后仅为原来的1/4,效率大大提高。
八、使用jsonp
对于一些不重要的请求,如淘宝的词汇联想,完全可以交给其他服务器,一个简单的jsonp就可以减轻服务器压力。
九、css外链放在head里面,js外链放在body后面
当我们的浏览器获得html文件后,会自上而下的加载,并在加载过程中进行解析和渲染。
遇到外链的css时候,会发起一个异步的css请求,不会影响dom树。
但是css慢的话,会使得页面闪烁,所以建议放在head里面。
遇到外链的js时候,html渲染线程就会挂起,等待js操作,因为js可能操作dom。
所以js外链要放在后面。
当所有的css下载结束,会构建cssom树,并和dom一个合成render树。
十、懒加载
对于不需要马上用到的css,js,img采用懒加载。
sea.js和require.js都是不错的选择
十一、代码细节层面
1.代码的阻塞
- 把js放在body后面,把css放在body前面,防止html渲染被阻塞。
- js提供了异步处理机制,如ajax, 回调函数, setTimeout等方法,尤其是回调函数和setTimeout,妙不可言。
2.代码重复
- 将重复逻辑合并。
- 使用学习模式编写代码,避免重复逻辑。
3.内存开销太大
- 避免复杂的运算出现,或采用记忆函数存储昂贵的计算结果。
- 优化局部算法,如快速排序法优于冒泡排序法。
- 采用一些数据结构,调整时间和空间的关系。
- .频繁使用的方法,尽量采用字符串处理,少用正则表达式。
- .即时清理掉废弃变量,特别是闭包中变量,更难察觉。
4.代码变量的优化
- 注意用变量接受常用变量。
- 缩短变量的查找链,变量的查找是 局部变量 -> 函数参数 -> 外部变量 -> 全局变量。
- 函数的声明性能从优到差的是:函数表达式方式 -> 函数声明方式 -> 使用Function构造函数。
5.频繁dom操作
- 使用一些模板可以减少dom操作。
- 尽量缓存dom元素,不要每次都去选择。
- 利用事件冒泡,可以减少dom事件的绑定。
- 节流器可以避免类似与抖动的操作。
- 使用第三方,如vue,react。
十二、css层面
1.选择器的效率由高到低
- ID选择器 比如#header
- 类选择器 比如.promo
- 元素选择器 比如 div
- 兄弟选择器 比如 h2 + p
- 子选择器 比如 li > ul
- 后代选择器 比如 ul a 7. 通用选择器 比如 *
- 属性选择器 比如 type = “text”
- 伪类/伪元素选择器 比如 a:hover
其中,ID选择器和类选择器差别不大。
通过谷歌调试工具可以看出来渲染时间的差别
2. css解析顺序
div#id .my-box a{
width: 100px;
height: 100px;
background: red;
}
上面css的解析是从右向左执行,先遍历到a 然后向上遍历到.my-box ,再向上遍历到#id,再匹配div。
3. 如何高效
- 尽量使用id加类选择器。
#div .link{}
/*优于*/
#div a{}
因为a标签的个数太多了,会加大浏览器的解析难度。
- 减少选择层级
#div li span a{}
就会给浏览器解析增加判断。
优化成:
#div a{}
或者
#div .link{}
推荐二级式的,#id .class{}