前端性能优化不完全手册
- - SegmentFault 最新的文章性能优化是一门大学问,本文仅对个人一些积累知识的阐述,欢迎下面补充. 抛出一个问题,从输入 url地址栏到所有内容显示到界面上做了哪些事. DNS 服务器请求解析该 URL 中的域名所对应的. 2.建立 TCP连接(三次握手);. 3.浏览器发出读取文件( URL 中域名后面部分对应的文件)的 HTTP 请求,该请求报文作为.
抛出一个问题,从输入 url
地址栏到所有内容显示到界面上做了哪些事?
DNS
服务器请求解析该 URL 中的域名所对应的 IP
地址;TCP
连接(三次握手);URL
中域名后面部分对应的文件)的 HTTP
请求,该请求报文作为 TCP
三次握手的第三个报文的数据发送给服务器;html
文本并显示内容;TCP
连接(四次挥手);上面这个问题是一个面试官非常喜欢问的问题,我们下面把这6个步骤分解,逐步细谈优化。
DNS
解析DNS`解析:将域名解析为ip地址 ,由上往下匹配,只要命中便停止
优化策略:尽量允许使用浏览器的缓存,能给我们节省大量时间。
TCP
的三次握手SYN (同步序列编号)ACK(确认字符)
优化策略:
HTTP
协议通信最耗费时间的是建立 TCP
连接的过程,那我们就可以使用 HTTP Keep-Alive
,在 HTTP
早期,每个 HTTP
请求都要求打开一个 TCP socket
连接,并且使用一次之后就断开这个 TCP
连接。 使用 keep-alive
可以改善这种状态,即在一次TCP连接中可以持续发送多份数据而不会断开连接。通过使用 keep-alive
机制,可以减少 TCP
连接建立次数,也意味着可以减少 TIME_WAIT
状态连接,以此提高性能和提高 http
服务器的吞吐率(更少的 tcp
连接意味着更少的系统内核调用keep-alive
并不是免费的午餐,长时间的 TCP
连接容易导致系统资源无效占用。配置不当的 keep-alive
,有时比重复利用连接带来的损失还更大。所以,正确地设置 keep-alive timeout
时间非常重要。(这个 keep-alive_timout
时间值意味着:一个 http
产生的 tcp
连接在传送完最后一个响应后,还需要 hold
住 keepalive_timeout
秒后,才开始关闭这个连接),如果想更详细了解可以看这篇文章 keep-alve性能优化的测试结果
webScoket
通信协议,仅一次 TCP
握手就一直保持连接,而且他对二进制数据的传输有更好的支持,可以应用于即时通信,海量高并发场景。 webSocket的原理以及详解
HTTP
请求次数,每次 HTTP
请求都会有请求头,返回响应都会有响应头,多次请求不仅浪费时间而且会让网络传输很多无效的资源,使用前端模块化技术 AMD CMD commonJS ES6等模块化方案
将多个文件压缩打包成一个,当然也不能都放在一个文件中,因为这样传输起来可能会很慢,权衡取一个中间值html
文件DOM
树css
标记,调用css解析器将其解析 CSSOM
树link
阻塞 - 为了解决闪屏,所有解决闪屏的样式style
非阻塞,与闪屏的样式不相关的DOM
树和 CSSOM
树结合在一起,形成 render
树script
标签,阻塞,调用 js
解析器解析 js
代码,可能会修改 DOM
树,也可能会修改 CSSOM
树DOM
树和 CSSOM
树结合在一起,形成 render
树layout
布局 render
渲染(重排重绘) script
标签的属性
性能优化策略:
link
引入,不需要的使用 style
标签(具体是否需要阻塞看业务场景)webpack4
中也要配置图片压缩,能极大压缩图片大小,对于新版本浏览器可以使用 webp格式图片
webP详解,图片优化对性能提升最大。webpack4
配置 代码分割,提取公共代码成单独模块。方便缓存 /*
runtimeChunk 设置为 true, webpack 就会把 chunk 文件名全部存到一个单独的 chunk 中,
这样更新一个文件只会影响到它所在的 chunk 和 runtimeChunk,避免了引用这个 chunk 的文件也发生改变。
*/
runtimeChunk: true,
splitChunks: {
chunks: 'all' // 默认 entry 的 chunk 不会被拆分, 配置成 all, 就可以了
}
}
//因为是单入口文件配置,所以没有考虑多入口的情况,多入口是应该分别进行处理。
webpack4
配置懒加载的,可以看这篇 webpack4优化教程,写得非常全面javaScript
的 DOM
操作等优化会在下面总结TCP
的四次挥手,断开连接 RAIL
Responce
响应,研究表明,100ms内对用户的输入操作进行响应,通常会被人类认为是立即响应。时间再长,操作与反应之间的连接就会中断,人们就会觉得它的操作有延迟。例如:当用户点击一个按钮,如果100ms内给出响应,那么用户就会觉得响应很及时,不会察觉到丝毫延迟感。Animaton
现如今大多数设备的屏幕刷新频率是60Hz,也就是每秒钟屏幕刷新60次;因此网页动画的运行速度只要达到60FPS,我们就会觉得动画很流畅。Idle
RAIL规定,空闲周期内运行的任务不得超过50ms,当然不止RAIL规定,W3C性能工作组的Longtasks标准也规定了超过50毫秒的任务属于长任务,那么50ms这个数字是怎么得来的呢?浏览器是单线程的,这意味着同一时间主线程只能处理一个任务,如果一个任务执行时间过长,浏览器则无法执行其他任务,用户会感觉到浏览器被卡死了,因为他的输入得不到任何响应。为了达到100ms内给出响应,将空闲周期执行的任务限制为50ms意味着,即使用户的输入行为发生在空闲任务刚开始执行,浏览器仍有剩余的50ms时间用来响应用户输入,而不会产生用户可察觉的延迟。Load
如果不能在1秒钟内加载网页并让用户看到内容,用户的注意力就会分散。用户会觉得他要做的事情被打断,如果10秒钟还打不开网页,用户会感到失望,会放弃他们想做的事,以后他们或许都不会再回来。如何使网页更丝滑?
使用requestAnimationFrame
避免 FSL
先执行 JS
,然后在 JS
中修改了样式从而导致样式计算,然后样式的改动触发了布局、绘制、合成。但 JavaScript
可以强制浏览器将布局提前执行,这就叫 强制同步布局 FSL
。
//读取offsetWidth的值会导致重绘
const newWidth = container.offsetWidth;
//设置width的值会导致重排,但是for循环内部
代码执行速度极快,当上面的查询操作导致的重绘
还没有完成,下面的代码又会导致重排,而且这个重
排会强制结束上面的重绘,直接重排,这样对性能影响
非常大。所以我们一般会在循环外部定义一个变量,这里
面使用变量代替container.offsetWidth;
boxes[i].style.width = newWidth + 'px';
}
transform
属性去操作动画,这个属性是由合成器单独处理的,所以使用这个属性可以避免布局与绘制。translateZ(0)
开启图层,减少重绘重排。特别在移动端,尽量使用 transform
代替 absolute
。创建图层的最佳方式是使用will-change,但某些不支持这个属性的浏览器可以使用3D 变形(transform: translateZ(0))来强制创建一个新层。class
,通过 class
的切换批量修改样式,避免多次重绘重排display:none
再修改样式append
操作可以先插入到一个新生成的元素中,再一次性插入到页面中。React
中封装成高阶组件, ES6
中可以使用继承, TypeScript
中接口继承,类继承,接口合并,类合并。以上都是根据本人的知识点总结得出,后期还会有 React
的性能优化方案等出来,路过点个赞收藏收藏~,欢迎提出问题补充~