网站性能小分析

457 阅读24分钟
网页性能的重要性
如果网站的打开速度慢或者卡顿假死严重影响用户的体验,进而影响产品使用的口碑和品牌或是带来经济上的损失
网页性能的重要性已经我们已经清楚,如何让一个网页变得更快,具体的是指哪些?
实际情况是性能是相对的:
  • 一个网站一个用户觉得很快、但其他用户感觉很慢。
  • 两个网站loading结束时间是一样的,但其中一个你感觉比另外一个要快。
  • 一个网站加载得很快但是页面长时间不可交互。
以上这些都是有感知的所以在讨论性能的时候,精确的,可量化的指标很重要的。
定义指标
之前开发者都是load事件来衡量网页性能但是load是页面生命周期中的准确时间,但是这个时间用户并不关心。
比方说:服务器返回了一个页面,或者打开一个静态页面,在load事件之后推迟了几秒来获取内容并展示。虽然这种页面load很快,但是实际上用户看到的内容则是在之后的几秒后的,load时间跟用户的实际感知是不一样的。
综上所述:Chrome团队围绕一系列问题定制来如下指标框架:
  • 是否发生了:跳转是否成功?服务器是否响应?
  • 是否有用:是否渲染了足够内容供用户查看?
  • 是否可用 :是否是可交互?
  • 是否流畅:交互无卡顿?无延后?顺畅?
指标分类
  • 感知加载速度:页面加载完毕并给用户呈现了展现内容
  • 加载响应:页面加载到js可交互
  • 运行时响应:页面加载完之后,到页面可交互
  • 视觉稳定性:页面是否有干扰元素,例如预期之外的滚动或者移动
  • 流畅性:transition和animation是否流畅,帧率是否保持在60
以上的所有分类,没有单一的指标可用于捕获3所有性能特征。
常见的性能指标
  • First contentful paint (FCP): 从页面开始加载,到页面任意内容渲染在屏幕上的时间。(实验属性,现场数据)
  • Largest contentful paint (LCP): 从页面加载开始,到页面上最大的文本块或者图片元素渲染在屏幕上的时间。(实验数据,现场数据)
  • First input delay (FID): 用户第一个交互行为,比如点击链接、点击按钮等,到浏览器实际响应这次交互的时间。(现场数据)
  • Time to Interactive (TTI): 从页面开始加载,到内容呈现,初始js加载完成,再到可以立刻响应用户交互的时间。(实验数据)
  • Total blocking time (TBT): 在FCP和TTI之间的时间,即页面可见到可交互的时间,代表了主线程被阻塞无法响应用户交互。(实验数据)
  • Cumulative layout shift (CLS): 从页面开始加载,到页面生命周期变为隐藏之间的所有意外的布局变化的累计分数。(实验数据,现场数据)
以上指标可以检测大部分的与用户相关的性能影响,但也不代表全部。
在某些情况下,会引入新的指标来覆盖缺失的区域,但其他情况下最好的指标是针对你的网站量身定制的。
使用性能API
你可以通过以下方法来探测和兼容performance:
var performance = window.performance || window.msPerformance || window.webkitPerformance; if (performance) { // 你的代码 }
performance的结构:
[https://pic1.zhimg.com/80/v2-bea3d9fa26e8f5ef736fc8de1f231740_1440w.png](https://pic1.zhimg.com/80/v2-bea3d9fa26e8f5ef736fc8de1f231740_1440w.png)
performance.memory是显示此刻内存占用情况,它是一个动态值,其中: usedJSHeapSize表示:JS 对象(包括V8引擎内部对象)占用的内存数 totalJSHeapSize表示:可使用的内存 jsHeapSizeLimit表示:内存大小限制 通常,usedJSHeapSize不能大于totalJSHeapSize,如果大于,有可能出现了内存泄漏。
performance.navigation显示页面的来源信息,其中: redirectCount表示:如果有重定向的话,页面通过几次重定向跳转而来,默认为0 type表示页面打开的方式, 0 表示 TYPE_NAVIGATENEXT 正常进入的页面(非刷新、非重定向等) 1 表示 TYPE_RELOAD 通过 window.location.reload() 刷新的页面 2 表示 TYPE_BACK_FORWARD 通过浏览器的前进后退按钮进入的页面(历史记录) 255 表示 TYPE_UNDEFINED 非以上方式进入的页面
performance.onresourcetimingbufferfull属性是一个在resourcetimingbufferfull事件触发时会被调用的 event handler 。它的值是一个手动设置的回调函数,这个回调函数会在浏览器的资源时间性能缓冲区满时执行。
performance.timeOrigin是一系列时间点的基准点,精确到万分之一毫秒。
performance.timing是一系列关键时间点,它包含了网络、解析等一系列的时间数据。
timing: { 
 // 同一个浏览器上一个页面卸载(unload)结束时的时间戳。如果没有上一个页面,这个值会和fetchStart相同。 navigationStart: 1543806782096, 

 // 上一个页面unload事件抛出时的时间戳。如果没有上一个页面,这个值会返回0。 unloadEventStart: 1543806782523, // 和 unloadEventStart 相对应,unload事件处理完成时的时间戳。如果没有上一个页面,这个值会返回0。 unloadEventEnd: 1543806782523, // 第一个HTTP重定向开始时的时间戳。如果没有重定向,或者重定向中的一个不同源,这个值会返回0。 redirectStart: 0, // 最后一个HTTP重定向完成时(也就是说是HTTP响应的最后一个比特直接被收到的时间)的时间戳。 // 如果没有重定向,或者重定向中的一个不同源,这个值会返回0. redirectEnd: 0, // 浏览器准备好使用HTTP请求来获取(fetch)文档的时间戳。这个时间点会在检查任何应用缓存之前。 fetchStart: 1543806782096, // DNS 域名查询开始的UNIX时间戳。 //如果使用了持续连接(persistent connection),或者这个信息存储到了缓存或者本地资源上,这个值将和fetchStart一致。 domainLookupStart: 1543806782096, // DNS 域名查询完成的时间. //如果使用了本地缓存(即无 DNS 查询)或持久连接,则与 fetchStart 值相等 domainLookupEnd: 1543806782096, // HTTP(TCP) 域名查询结束的时间戳。 //如果使用了持续连接(persistent connection),或者这个信息存储到了缓存或者本地资源上,这个值将和 fetchStart一致。 connectStart: 1543806782099, // HTTP(TCP) 返回浏览器与服务器之间的连接建立时的时间戳。 // 如果建立的是持久连接,则返回值等同于fetchStart属性的值。连接建立指的是所有握手和认证过程全部结束。 connectEnd: 1543806782227, // HTTPS 返回浏览器与服务器开始安全链接的握手时的时间戳。如果当前网页不要求安全连接,则返回0。 secureConnectionStart: 1543806782162, // 返回浏览器向服务器发出HTTP请求时(或开始读取本地缓存时)的时间戳。 requestStart: 1543806782241, // 返回浏览器从服务器收到(或从本地缓存读取)第一个字节时的时间戳。 //如果传输层在开始请求之后失败并且连接被重开,该属性将会被数制成新的请求的相对应的发起时间。 responseStart: 1543806782516, // 返回浏览器从服务器收到(或从本地缓存读取,或从本地资源读取)最后一个字节时 //(如果在此之前HTTP连接已经关闭,则返回关闭时)的时间戳。 responseEnd: 1543806782537, // 当前网页DOM结构开始解析时(即Document.readyState属性变为“loading”、相应的 readystatechange事件触发时)的时间戳。 domLoading: 1543806782573, // 当前网页DOM结构结束解析、开始加载内嵌资源时(即Document.readyState属性变为“interactive”、相应的readystatechange事件触发时)的时间戳。 domInteractive: 1543806783203, // 当解析器发送DOMContentLoaded 事件,即所有需要被执行的脚本已经被解析时的时间戳。 domContentLoadedEventStart: 1543806783203, // 当所有需要立即执行的脚本已经被执行(不论执行顺序)时的时间戳。 domContentLoadedEventEnd: 1543806783216, // 当前文档解析完成,即Document.readyState 变为 'complete'且相对应的readystatechange 被触发时的时间戳 domComplete: 1543806783796, // load事件被发送时的时间戳。如果这个事件还未被发送,它的值将会是0。 loadEventStart: 1543806783796, // 当load事件结束,即加载事件完成时的时间戳。如果这个事件还未被发送,或者尚未完成,它的值将会是0. loadEventEnd: 1543806783802 }

这些参数非常有用,可以帮助我们获取页面的Domready时间、onload时间、白屏时间等,以及单个页面资源在从发送请求到获取到rsponse各阶段的性能参数。
对我们比较有用的页面性能数据大概包括如下几个,这些参数是通过上面的performance.timing各个属性的差值组成的,它是精确到毫秒的一个值,计算方法如下:
重定向耗时:redirectEnd - redirectStart
DNS查询耗时 :domainLookupEnd - domainLookupStart
TCP链接耗时 :connectEnd - connectStart
HTTP请求耗时 :responseEnd - responseStart
解析dom树耗时 : domComplete - domInteractive
白屏时间 :responseStart - navigationStart
DOMready时间 :domContentLoadedEventEnd - navigationStart
onload时间:loadEventEnd - navigationStart,也即是onload回调函数执行的时间。
如何优化?
**重定向优化:**重定向的类型分三种,301(永久重定向),302(临时重定向),304(Not Modified)。304是用来优化缓存,非常有用,而前两种应该尽可能的避免,凡是遇到需要重定向跳转代码的代码,可以把重定向之后的地址直接写到前端的html或JS中,可以减少客户端与服务端的通信过程,节省重定向耗时。
**DNS优化:**一般来说,在前端优化中与 DNS 有关的有两点: 一个是减少DNS的请求次数,另一个就是进行DNS预获取(Prefetching ) 。典型的一次DNS解析需要耗费 20-120 毫秒(移动端会更慢),减少DNS解析的次数是个很好的优化方式,尽量把各种资源放在一个cdn域名上。DNS Prefetching 是让具有此属性的域名不需要用户点击链接就在后台解析,而域名解析和内容载入是串行的网络操作,所以这个方式能减少用户的等待时间,提升用户体验 。新版的浏览器会对页面中和当前域名(正在浏览网页的域名)不在同一个域的域名进行预获取,并且缓存结果,这就是隐式的 DNS Prefetch。如果想对页面中没有出现的域进行预获取,那么就要使用显示的 DNS Prefetch 了。下图是DNS Prefetch的方法:
xxx
**TCP请求优化:**TCP的优化大都在服务器端,前端能做的就是尽量减少TCP的请求数,也就是减少HTTP的请求数量。http 1.0 默认使用短连接,也是TCP的短连接,也就是客户端和服务端每进行一次http操作,就建立一次连接,任务结束就中断连接。这个过程中有3次TCP请求握手和4次TCP请求释放。减少TCP请求的方式有两种,一种是资源合并,对于页面内的图片、css和js进行合并,减少请求量。另一种使用长链接,使用http1.1,在HTTP的响应头会加上 Connection:keep-alive,当一个网页打开完成之后,连接不会马上关闭,再次访问这个服务时,会继续使用这个长连接。这样就大大减少了TCP的握手次数和释放次数。或者使用Websocket进行通信,全程只需要建立一次TCP链接。
**HTTP请求优化:**使用内容分发网络(CDN)和减少请求。使用CDN可以减少网络的请求时延,CDN的域名不要和主站的域名一样,这样会防止访问CDN时还携带主站cookie的问题,对于网络请求,可以使用fetch发送无cookie的请求,减少http包的大小。也可以使用本地缓存策略,尽量减少对服务器数据的重复获取。
**渲染优化:**在浏览器端的渲染过程,如大型框架,vue和react,它的模板其实都是在浏览器端进行渲染的,不是直出的html,而是要走框架中相关的框架代码才能去渲染出页面,这个渲染过程对于首屏就有较大的损耗,白屏的时间会有所增加。在必要的情况下可以在服务端进行整个html的渲染,从而将整个html直出到我们的浏览器端,而非在浏览器端进行渲染。
网页性能的重要性
如果网站的打开速度慢或者卡顿假死严重影响用户的体验,进而影响产品使用的口碑和品牌或是带来经济上的损失
网页性能的重要性已经我们已经清楚,如何让一个网页变得更快,具体的是指哪些?
实际情况是性能是相对的:
  • 一个网站一个用户觉得很快、但其他用户感觉很慢。
  • 两个网站loading结束时间是一样的,但其中一个你感觉比另外一个要快。
  • 一个网站加载得很快但是页面长时间不可交互。
以上这些都是有感知的所以在讨论性能的时候,精确的,可量化的指标很重要的。
定义指标
之前开发者都是load事件来衡量网页性能但是load是页面生命周期中的准确时间,但是这个时间用户并不关心。
比方说:服务器返回了一个页面,或者打开一个静态页面,在load事件之后推迟了几秒来获取内容并展示。虽然这种页面load很快,但是实际上用户看到的内容则是在之后的几秒后的,load时间跟用户的实际感知是不一样的。
综上所述:Chrome团队围绕一系列问题定制来如下指标框架:
  • 是否发生了:跳转是否成功?服务器是否响应?
  • 是否有用:是否渲染了足够内容供用户查看?
  • 是否可用 :是否是可交互?
  • 是否流畅:交互无卡顿?无延后?顺畅?
指标分类
  • 感知加载速度:页面加载完毕并给用户呈现了展现内容
  • 加载响应:页面加载到js可交互
  • 运行时响应:页面加载完之后,到页面可交互
  • 视觉稳定性:页面是否有干扰元素,例如预期之外的滚动或者移动
  • 流畅性:transition和animation是否流畅,帧率是否保持在60
以上的所有分类,没有单一的指标可用于捕获3所有性能特征。
常见的性能指标
  • First contentful paint (FCP): 从页面开始加载,到页面任意内容渲染在屏幕上的时间。(实验属性,现场数据)
  • Largest contentful paint (LCP): 从页面加载开始,到页面上最大的文本块或者图片元素渲染在屏幕上的时间。(实验数据,现场数据)
  • First input delay (FID): 用户第一个交互行为,比如点击链接、点击按钮等,到浏览器实际响应这次交互的时间。(现场数据)
  • Time to Interactive (TTI): 从页面开始加载,到内容呈现,初始js加载完成,再到可以立刻响应用户交互的时间。(实验数据)
  • Total blocking time (TBT): 在FCP和TTI之间的时间,即页面可见到可交互的时间,代表了主线程被阻塞无法响应用户交互。(实验数据)
  • Cumulative layout shift (CLS): 从页面开始加载,到页面生命周期变为隐藏之间的所有意外的布局变化的累计分数。(实验数据,现场数据)
以上指标可以检测大部分的与用户相关的性能影响,但也不代表全部。
在某些情况下,会引入新的指标来覆盖缺失的区域,但其他情况下最好的指标是针对你的网站量身定制的。
使用性能API
你可以通过以下方法来探测和兼容performance:
var performance = window.performance || window.msPerformance || window.webkitPerformance; if (performance) { // 你的代码 }
performance的结构:
[https://pic1.zhimg.com/80/v2-bea3d9fa26e8f5ef736fc8de1f231740_1440w.png](https://pic1.zhimg.com/80/v2-bea3d9fa26e8f5ef736fc8de1f231740_1440w.png)
performance.memory是显示此刻内存占用情况,它是一个动态值,其中: usedJSHeapSize表示:JS 对象(包括V8引擎内部对象)占用的内存数 totalJSHeapSize表示:可使用的内存 jsHeapSizeLimit表示:内存大小限制 通常,usedJSHeapSize不能大于totalJSHeapSize,如果大于,有可能出现了内存泄漏。
performance.navigation显示页面的来源信息,其中: redirectCount表示:如果有重定向的话,页面通过几次重定向跳转而来,默认为0 type表示页面打开的方式, 0 表示 TYPE_NAVIGATENEXT 正常进入的页面(非刷新、非重定向等) 1 表示 TYPE_RELOAD 通过 window.location.reload() 刷新的页面 2 表示 TYPE_BACK_FORWARD 通过浏览器的前进后退按钮进入的页面(历史记录) 255 表示 TYPE_UNDEFINED 非以上方式进入的页面
performance.onresourcetimingbufferfull属性是一个在resourcetimingbufferfull事件触发时会被调用的 event handler 。它的值是一个手动设置的回调函数,这个回调函数会在浏览器的资源时间性能缓冲区满时执行。
performance.timeOrigin是一系列时间点的基准点,精确到万分之一毫秒。
performance.timing是一系列关键时间点,它包含了网络、解析等一系列的时间数据。
timing: { // 同一个浏览器上一个页面卸载(unload)结束时的时间戳。

如果没有上一个页面,这个值会和fetchStart相同。 navigationStart: 1543806782096, // 上一个页面unload事件抛出时的时间戳。

如果没有上一个页面,这个值会返回0。 unloadEventStart: 1543806782523, // 和 unloadEventStart 相对应,unload事件处理完成时的时间戳。

如果没有上一个页面,这个值会返回0。 unloadEventEnd: 1543806782523, // 第一个HTTP重定向开始时的时间戳。如果没有重定向,或者重定向中的一个不同源,这个值会返回0。 redirectStart: 0, // 最后一个HTTP重定向完成时(也就是说是HTTP响应的最后一个比特直接被收到的时间)的时间戳。

 // 如果没有重定向,或者重定向中的一个不同源,这个值会返回0. redirectEnd: 0,

 // 浏览器准备好使用HTTP请求来获取(fetch)文档的时间戳。这个时间点会在检查任何应用缓存之前。 fetchStart: 1543806782096, 

 // DNS 域名查询开始的UNIX时间戳。

 //如果使用了持续连接(persistent connection),或者这个信息存储到了缓存或者本地资源上,这个值将和fetchStart一致。 domainLookupStart: 1543806782096, 

 // DNS 域名查询完成的时间. //如果使用了本地缓存(即无 DNS 查询)或持久连接,则与 fetchStart 值相等 domainLookupEnd: 1543806782096, 

 // HTTP(TCP) 域名查询结束的时间戳。

 //如果使用了持续连接(persistent connection),或者这个信息存储到了缓存或者本地资源上,这个值将和 fetchStart一致。 connectStart: 1543806782099, 

 // HTTP(TCP) 返回浏览器与服务器之间的连接建立时的时间戳。

 // 如果建立的是持久连接,则返回值等同于fetchStart属性的值。连接建立指的是所有握手和认证过程全部结束。 connectEnd: 1543806782227, 

 // HTTPS 返回浏览器与服务器开始安全链接的握手时的时间戳。如果当前网页不要求安全连接,则返回0。 secureConnectionStart: 1543806782162, // 返回浏览器向服务器发出HTTP请求时(或开始读取本地缓存时)的时间戳。 requestStart: 1543806782241, // 返回浏览器从服务器收到(或从本地缓存读取)第一个字节时的时间戳。 //如果传输层在开始请求之后失败并且连接被重开,该属性将会被数制成新的请求的相对应的发起时间。 responseStart: 1543806782516, // 返回浏览器从服务器收到(或从本地缓存读取,或从本地资源读取)最后一个字节时 //(如果在此之前HTTP连接已经关闭,则返回关闭时)的时间戳。 responseEnd: 1543806782537, // 当前网页DOM结构开始解析时(即Document.readyState属性变为“loading”、相应的 readystatechange事件触发时)的时间戳。 domLoading: 1543806782573, // 当前网页DOM结构结束解析、开始加载内嵌资源时(即Document.readyState属性变为“interactive”、相应的readystatechange事件触发时)的时间戳。 domInteractive: 1543806783203, // 当解析器发送DOMContentLoaded 事件,即所有需要被执行的脚本已经被解析时的时间戳。 domContentLoadedEventStart: 1543806783203, // 当所有需要立即执行的脚本已经被执行(不论执行顺序)时的时间戳。 domContentLoadedEventEnd: 1543806783216, // 当前文档解析完成,即Document.readyState 变为 'complete'且相对应的readystatechange 被触发时的时间戳 domComplete: 1543806783796, // load事件被发送时的时间戳。如果这个事件还未被发送,它的值将会是0。 loadEventStart: 1543806783796, // 当load事件结束,即加载事件完成时的时间戳。如果这个事件还未被发送,或者尚未完成,它的值将会是0. loadEventEnd: 1543806783802 }

这些参数非常有用,可以帮助我们获取页面的Domready时间、onload时间、白屏时间等,以及单个页面资源在从发送请求到获取到rsponse各阶段的性能参数。
对我们比较有用的页面性能数据大概包括如下几个,这些参数是通过上面的performance.timing各个属性的差值组成的,它是精确到毫秒的一个值,计算方法如下:
重定向耗时:redirectEnd - redirectStart
DNS查询耗时 :domainLookupEnd - domainLookupStart
TCP链接耗时 :connectEnd - connectStart
HTTP请求耗时 :responseEnd - responseStart
解析dom树耗时 : domComplete - domInteractive
白屏时间 :responseStart - navigationStart
DOMready时间 :domContentLoadedEventEnd - navigationStart
onload时间:loadEventEnd - navigationStart,也即是onload回调函数执行的时间。
如何优化?
**重定向优化:**重定向的类型分三种,301(永久重定向),302(临时重定向),304(Not Modified)。304是用来优化缓存,非常有用,而前两种应该尽可能的避免,凡是遇到需要重定向跳转代码的代码,可以把重定向之后的地址直接写到前端的html或JS中,可以减少客户端与服务端的通信过程,节省重定向耗时。
**DNS优化:**一般来说,在前端优化中与 DNS 有关的有两点: 一个是减少DNS的请求次数,另一个就是进行DNS预获取(Prefetching ) 。典型的一次DNS解析需要耗费 20-120 毫秒(移动端会更慢),减少DNS解析的次数是个很好的优化方式,尽量把各种资源放在一个cdn域名上。DNS Prefetching 是让具有此属性的域名不需要用户点击链接就在后台解析,而域名解析和内容载入是串行的网络操作,所以这个方式能减少用户的等待时间,提升用户体验 。新版的浏览器会对页面中和当前域名(正在浏览网页的域名)不在同一个域的域名进行预获取,并且缓存结果,这就是隐式的 DNS Prefetch。如果想对页面中没有出现的域进行预获取,那么就要使用显示的 DNS Prefetch 了。下图是DNS Prefetch的方法:
<html>
<head>
  <title>腾讯网</title>
  <link rel="dns-prefetch" href="//mat1.gtimg.com"  />
  <link rel="dns-prefetch" href="//inews.gtimg.com"  />
  <link rel="dns-prefetch" href="//wx.qlogo.cn"  />
  <link rel="dns-prefetch" href="//coral.qq.com" />
  <link rel="dns-prefetch" href="//pingjs.qq.com"  />
**TCP请求优化:**TCP的优化大都在服务器端,前端能做的就是尽量减少TCP的请求数,也就是减少HTTP的请求数量。http 1.0 默认使用短连接,也是TCP的短连接,也就是客户端和服务端每进行一次http操作,就建立一次连接,任务结束就中断连接。这个过程中有3次TCP请求握手和4次TCP请求释放。减少TCP请求的方式有两种,一种是资源合并,对于页面内的图片、css和js进行合并,减少请求量。另一种使用长链接,使用http1.1,在HTTP的响应头会加上 Connection:keep-alive,当一个网页打开完成之后,连接不会马上关闭,再次访问这个服务时,会继续使用这个长连接。这样就大大减少了TCP的握手次数和释放次数。或者使用Websocket进行通信,全程只需要建立一次TCP链接。
**HTTP请求优化:**使用内容分发网络(CDN)和减少请求。使用CDN可以减少网络的请求时延,CDN的域名不要和主站的域名一样,这样会防止访问CDN时还携带主站cookie的问题,对于网络请求,可以使用fetch发送无cookie的请求,减少http包的大小。也可以使用本地缓存策略,尽量减少对服务器数据的重复获取。
**渲染优化:**在浏览器端的渲染过程,如大型框架,vue和react,它的模板其实都是在浏览器端进行渲染的,不是直出的html,而是要走框架中相关的框架代码才能去渲染出页面,这个渲染过程对于首屏就有较大的损耗,白屏的时间会有所增加。在必要的情况下可以在服务端进行整个html的渲染,从而将整个html直出到我们的浏览器端,而非在浏览器端进行渲染。
![](//note.youdao.com/src/97FF48F680FD45D3BD3F7F8E3FD747D6)
还有一个问题就是,在默认情况下,JavaScript 执行会“阻止解析器”,当浏览器遇到一个 script 外链标记时,DOM 构建将暂停,会将控制权移交给 JavaScript 运行时,等脚本下载执行完毕,然后再继续构建 DOM。而且内联脚本始终会阻止解析器,除非编写额外代码来推迟它们的执行。我们可以把 script 外链加入到页面底部,也可以使用 defer 或 async 延迟执行。defer 和 async 的区别就是 defer 是有序的,代码的执行按在html中的先后顺序,而 async 是无序的,只要下载完毕就会立即执行。或者使用异步的编程方法,比如settimeout,也可以使用多线webworker,它们不会阻碍 DOM 的渲染。
tips:建立前端监控系统:然后根据监控的性能的指标针对网站的各项指标针对性的去优化:
根据目前大部分的开发技术栈不是react就是vue,利用webpack将非开发的环境的依赖包进行cdn管理