We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
在互联网,速度是关键。很多案例已经证明:
在前端领域,性能优化有两个主要目的:
目前,一个普通的Web应用大约就有1MB,有100个左右的资源分散在15台不同的主机上。优化网络请求势在必行。
对于网络请求,有两个指标指示请求的质量:延迟和带宽。
延迟,分组从信息源发送到目的地所需的时间 带宽,逻辑或物理通信路径最大的吞吐量
客户端到服务器的总延迟时间包括:
对于带宽,目前小区带宽普遍百兆光纤,4G移动网络,就上下行速率来说,可以看成是一个百兆级的宽带,现在比较普遍的100M宽带的下行是100Mbps,上行是20Mbps。
那么延迟和带宽,哪个才是影响网络体验的关键呢?
可以看看下图,某网址首页加载html静态资源的Timing图:
蓝色部分是下载数据需要的时间,它是受带宽影响的;其它部分都是延迟影响的,特别是绿色部分(Waiting),它是受传播延迟影响的,橙色部分是建立TCP连接花费的时间,紫色部分是其中建立SSL花费的世界。很显然,在现在互联网时代,带宽不再是网络体验的瓶颈,延迟才是。
TTFT,Time To First Byte,接收到第一个字节所需要的时间
让我们理清资源交互过程。一次请求过程,包括建立TCP、TLS,然后是发送HTTP报文,等待HTTP响应。
建立TCP连接需要三次握手,那么就相当于放大三倍延迟,所以提高TCP应用性能的关键,在于想办法重用连接,当然,如果能从逻辑上减少握手的步骤也是一种策略,TFO就是其中一种策略。
TFO(TCP Fast Open,TCP快速打开)通过握手开始时的SYN包中的TFO cookie(一个TCP选项)来验证一个之前连接过的客户端。如果验证成功,它可以在三次握手最终的ACK包收到之前就开始发送数据,这样便跳过了一个绕路的行为,更在传输开始时就降低了延迟。
重用TCP连接,目前已经广泛使用在HTTP1.1协议,保持长连接(Connection: keep-alive)便可以重用TCP连接,减少建立TCP花费的世界。
当然,如果使用UDP替代TCP将会彻底减少建立连接需要花费的世界,QUIC(快速UDP网络连接)就是基于这个原理。
在QUIC广泛应用之前,我们可以使用HTTP2达到最大程度重用TCP连接的目的。HTTP1.1时代为了加速网络访问,浏览器会为每个域名同时建立最多6个TCP连接用以摆脱HTTP队首阻塞。HTTP2是基于帧的,可以多路复用TCP连接,同域名的多个请求可以都重用TCP连接,减少建立TCP连接的耗时。
SSL/TLS的握手过程也是比较复杂的。大致过程就是,确定加密套件,校验服务器公钥,生成3个随机数,通过三个随机数生成对称加密密钥,校验密钥,传输加密信息。
为了减少握手的耗时。如果某次握手过程的 Client Hello 消息里还附带了上一次的 Session ID,服务端接收到这个 Session ID 并校验后如果能复用密钥就不再进行后续的握手过程。
ALPN(应用层协议协商)作为TLS扩展,能过在TLS握手的同事协商应用协议,从而可以省掉HTTP的Upgrade机制所需的额外往返时间。
延迟是跟距离相关的,原则上说,距离越短延迟越低,CDN服务就是基于这个原理。
把静态资源放在CDN服务上,可以有效降低静态资源请求的延迟。
CDN的核心是智能调度,它的底层实现原理依赖运营商,因为运营商有用户IP地址的元信息,还知道哪些地区有哪些IP可以提供服务。所以,在域名解析阶段去分析用户IP,返回最近最佳的服务器IP。
除了CDN,使用缓存可以通过减少请求次数达到减少延迟的效果。
对于HTTP1.X而已,优化是基于TCP协议特性的,具体策略是减少建立连接次数、减少请求数量、提升并发下载能力:
HTTP管道,原理是把FIFO队列从客户端(请求队列)迁移到服务器(响应队列)
对于HTTP2可以有效解决HTTP1.X遇到的问题,HTTP管道不会再发生队首阻塞,多路复用不需要建立多个TCP连接和域名分区,可以有效缓存小块资源不需要连接与拼合。
良好的用户体验可以降低用户对延迟的敏感度。
现代浏览器可以为我们做很多的优化:
现代浏览器的标签可以指示浏览器提前记载资源,它的rel属性有如下值:dns-prefetch、prefetch、prerender,分别指示浏览器预解析特定的域名、预取得将来导航要用的资源、根据对用户下一个目标的预测,预渲染特定页面
前端性能优化最重要的部分是图片优化。很多网站,图片资源的大小比JS+CSS还大。
图片优化主要有以下手段:
尽量使用硬件加速,下面三个style属性会使用GPU处理:
现代浏览器还支持使用 will-change 或 translateZ 把元素提升到一个独立的层。
如果一定要使用JS接口,请使用requestAnimationFrame(callback)接口,callback的回调带有一个参数——时间戳,值跟performance.now()的返回值相同,可以借助这个时间戳计算动画量。
requestAnimationFrame(callback)
performance.now()
浏览器上有一些事件是会持续发生的,比如滚动事件、拖拽事件、resize事件等等,这些事件会在每一帧开始前执行事件回调。
如果不是在这些事件上驱动动画的话,建议使用防抖节流的策略去处理事件。
防抖是将多次执行变为最后一次执行。
节流是将多次执行变为在规定时间内只执行一次。
可以通过下图看函数正常执行、防抖、节流的区别:
防抖适合的业务:
非立即执行版:input搜索框,客户输完过一会就会自动搜索;window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次;立即执行版:就是对于按钮防点击,例如点赞、心标、收藏等有立即反馈的按钮。
节流适合的业务:
鼠标不断点击触发,点击事件在规定时间内只触发一次(单位时间内只触发一次);监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断。
DOM是浏览器提供的描述文档元素的对象。
通过选择器去查询dom元素是比较耗时的,最好的做法就是用变量保存它。
关于回流和重绘,每当我们去修改一个dom元素的样式(包括几何尺寸和颜色),这个元素会被标记为dirty,并把更新操作(Recalc Styles、Layout【如果是重绘则跳过】、Update Layer Tree、Paint、Composite)放入下一帧更新队列里,浏览器会在合适的时机去更新dom元素。
dirty
几何尺寸包括:width、height、padding、margin、left、top、border等 颜色指背景色、字体色等等
如果此时访问元素的几何、定位属性,如offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight,就会触发强制回流、重绘,元素的dom.getBoundingClientRect();方法也会触发。
dom.getBoundingClientRect();
观察如下的代码,和它们的执行过程火焰图:
function test1() { var $0 = document.querySelector("#sidebar") $0.style.width = "800px"; } setTimeout(test1);
观察函数执行过程:
function test1() { var $0 = document.querySelector("#sidebar") $0.style.width = "800px"; $0.getBoundingClientRect(); } setTimeout(test1);
对比可以看出来,第二张图在函数test1里执行强制回流重绘,导致test1执行时间变长,这是兵家大忌。
使用3D加速的CSS属性之所以很快且流畅,是因为动画属性一经提交到GPU就不会再占用主线程了,也就是说该动画的整个过程不会触发Recalc Styles、Layout、Update Layer Tree、Paint、Composite。
《Web性能权威指南》 《前端性能优化原理与实践》,掘金
The text was updated successfully, but these errors were encountered:
No branches or pull requests
性能优化
在互联网,速度是关键。很多案例已经证明:
在前端领域,性能优化有两个主要目的:
优化网络请求
目前,一个普通的Web应用大约就有1MB,有100个左右的资源分散在15台不同的主机上。优化网络请求势在必行。
延迟和带宽
对于网络请求,有两个指标指示请求的质量:延迟和带宽。
客户端到服务器的总延迟时间包括:
对于带宽,目前小区带宽普遍百兆光纤,4G移动网络,就上下行速率来说,可以看成是一个百兆级的宽带,现在比较普遍的100M宽带的下行是100Mbps,上行是20Mbps。
那么延迟和带宽,哪个才是影响网络体验的关键呢?
可以看看下图,某网址首页加载html静态资源的Timing图:
蓝色部分是下载数据需要的时间,它是受带宽影响的;其它部分都是延迟影响的,特别是绿色部分(Waiting),它是受传播延迟影响的,橙色部分是建立TCP连接花费的时间,紫色部分是其中建立SSL花费的世界。很显然,在现在互联网时代,带宽不再是网络体验的瓶颈,延迟才是。
如何降低延迟
让我们理清资源交互过程。一次请求过程,包括建立TCP、TLS,然后是发送HTTP报文,等待HTTP响应。
对于TCP
建立TCP连接需要三次握手,那么就相当于放大三倍延迟,所以提高TCP应用性能的关键,在于想办法重用连接,当然,如果能从逻辑上减少握手的步骤也是一种策略,TFO就是其中一种策略。
TFO(TCP Fast Open,TCP快速打开)通过握手开始时的SYN包中的TFO cookie(一个TCP选项)来验证一个之前连接过的客户端。如果验证成功,它可以在三次握手最终的ACK包收到之前就开始发送数据,这样便跳过了一个绕路的行为,更在传输开始时就降低了延迟。
重用TCP连接,目前已经广泛使用在HTTP1.1协议,保持长连接(Connection: keep-alive)便可以重用TCP连接,减少建立TCP花费的世界。
当然,如果使用UDP替代TCP将会彻底减少建立连接需要花费的世界,QUIC(快速UDP网络连接)就是基于这个原理。
在QUIC广泛应用之前,我们可以使用HTTP2达到最大程度重用TCP连接的目的。HTTP1.1时代为了加速网络访问,浏览器会为每个域名同时建立最多6个TCP连接用以摆脱HTTP队首阻塞。HTTP2是基于帧的,可以多路复用TCP连接,同域名的多个请求可以都重用TCP连接,减少建立TCP连接的耗时。
对于SSL/TLS
SSL/TLS的握手过程也是比较复杂的。大致过程就是,确定加密套件,校验服务器公钥,生成3个随机数,通过三个随机数生成对称加密密钥,校验密钥,传输加密信息。
为了减少握手的耗时。如果某次握手过程的 Client Hello 消息里还附带了上一次的 Session ID,服务端接收到这个 Session ID 并校验后如果能复用密钥就不再进行后续的握手过程。
ALPN(应用层协议协商)作为TLS扩展,能过在TLS握手的同事协商应用协议,从而可以省掉HTTP的Upgrade机制所需的额外往返时间。
静态资源
延迟是跟距离相关的,原则上说,距离越短延迟越低,CDN服务就是基于这个原理。
把静态资源放在CDN服务上,可以有效降低静态资源请求的延迟。
CDN的核心是智能调度,它的底层实现原理依赖运营商,因为运营商有用户IP地址的元信息,还知道哪些地区有哪些IP可以提供服务。所以,在域名解析阶段去分析用户IP,返回最近最佳的服务器IP。
除了CDN,使用缓存可以通过减少请求次数达到减少延迟的效果。
HTTP协议
对于HTTP1.X而已,优化是基于TCP协议特性的,具体策略是减少建立连接次数、减少请求数量、提升并发下载能力:
对于HTTP2可以有效解决HTTP1.X遇到的问题,HTTP管道不会再发生队首阻塞,多路复用不需要建立多个TCP连接和域名分区,可以有效缓存小块资源不需要连接与拼合。
优化用户体验
良好的用户体验可以降低用户对延迟的敏感度。
浏览器优化
现代浏览器可以为我们做很多的优化:
现代浏览器的标签可以指示浏览器提前记载资源,它的rel属性有如下值:dns-prefetch、prefetch、prerender,分别指示浏览器预解析特定的域名、预取得将来导航要用的资源、根据对用户下一个目标的预测,预渲染特定页面
图片优化
前端性能优化最重要的部分是图片优化。很多网站,图片资源的大小比JS+CSS还大。
图片优化主要有以下手段:
动画优化
尽量使用硬件加速,下面三个style属性会使用GPU处理:
现代浏览器还支持使用 will-change 或 translateZ 把元素提升到一个独立的层。
如果一定要使用JS接口,请使用
requestAnimationFrame(callback)
接口,callback的回调带有一个参数——时间戳,值跟performance.now()
的返回值相同,可以借助这个时间戳计算动画量。交互优化
浏览器上有一些事件是会持续发生的,比如滚动事件、拖拽事件、resize事件等等,这些事件会在每一帧开始前执行事件回调。
如果不是在这些事件上驱动动画的话,建议使用防抖节流的策略去处理事件。
防抖是将多次执行变为最后一次执行。
节流是将多次执行变为在规定时间内只执行一次。
可以通过下图看函数正常执行、防抖、节流的区别:
防抖适合的业务:
非立即执行版:input搜索框,客户输完过一会就会自动搜索;window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次;立即执行版:就是对于按钮防点击,例如点赞、心标、收藏等有立即反馈的按钮。
节流适合的业务:
鼠标不断点击触发,点击事件在规定时间内只触发一次(单位时间内只触发一次);监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断。
DOM接口
DOM是浏览器提供的描述文档元素的对象。
通过选择器去查询dom元素是比较耗时的,最好的做法就是用变量保存它。
关于回流和重绘,每当我们去修改一个dom元素的样式(包括几何尺寸和颜色),这个元素会被标记为
dirty
,并把更新操作(Recalc Styles、Layout【如果是重绘则跳过】、Update Layer Tree、Paint、Composite)放入下一帧更新队列里,浏览器会在合适的时机去更新dom元素。如果此时访问元素的几何、定位属性,如offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight,就会触发强制回流、重绘,元素的
dom.getBoundingClientRect();
方法也会触发。观察如下的代码,和它们的执行过程火焰图:
观察函数执行过程:
对比可以看出来,第二张图在函数test1里执行强制回流重绘,导致test1执行时间变长,这是兵家大忌。
参考
《Web性能权威指南》
《前端性能优化原理与实践》,掘金
The text was updated successfully, but these errors were encountered: