网站性能优化

1. 什么样的性能指标值得我们关注

 1.1 原理

  • 可衡量,可以用代码来度量
  • 用户的真实体验及关键结果。关键结果就是指用户真正关注的是什么【进入商品详情页,用户关心商品描述、商品价格、商品描述、购买按钮等关键信息】;真实体验就是指用户使用产品的感受【在滑动时突然弹框,用户体验好不好】

1.2  指标

  •  加载:进入页面时,网页的载入过程
  •  交互:用户操作时,页面的反馈
  • 视觉稳定性指标(CLS/布局偏移量):页面从一帧切换到另一帧时,视线中不稳定元素的偏移情况【例如,点击购买页面链接购买时,原来的位置突然插入了一条9.9包邮的广告】

当前性能优化主要集中在加载方面,如白屏和首屏加载时间,且有相应的标准已达成业界共识,可手动或自动采集

交互性和视觉稳定性还没统一的标准,必须手动采集 

加载:

  • 白屏时间:从URL输入回车(包括刷新、跳转等方式)后到页面开始出现第一个字符的时间【标准时间:300ms】
  • 首屏时间:白屏时间 + 渲染时间,浏览器输入地址回车后的时间到首屏加载完成后的时间,这期间不需要滚动鼠标或下拉页面,否则无效

出现白屏时间的原因:

        1. DNS查询时间太长

        2. 建立TCP请求太慢

        3. 服务器处理请求太慢

        4. 客户端下载、解析、渲染时间过长

        5. 没有做Gzip压缩(压缩文件,网络传输文件时,减少传输时间。)

        6. 缺乏本地离线化处理

        ……

 页面加载的大致过程:

        1. 在浏览器中输入URL地址,本地缓存确认是否已经存在这个网站,如果没有,浏览器向DNS服务器发起DNS查询(为了把URL解析为IP地址),获取IP地址

        2. 浏览器通过IP地址找到目标服务器,TCP三次握手和TLS协商建立连接

        3. 建立连接后,浏览器可以发起http请求,服务器收到后,从数据存储层取到数据并对数据进行加工聚合,再返回给前端。

        4. 浏览器拿到数据后,对其进行解析和渲染,在用户面前展示网页

交互性:

  1. FID指标:首次输入延迟,指标必须尽量小于100ms
  2. PSI指标:视觉变化率,衡量标准是小于20%

视觉稳定性 :

    依赖Google的LightHouse做本地采集(除此之外,暂无其他方案)

2. 性能优化的瓶颈点

页面加载的大致过程可分为  客户端发起请求阶段(1,2)、服务器数据处理请求阶段(3的后半)、客户端页面解析渲染阶段(4)。 

2.1 客户端发起请求阶段 

         2.1.1 本地缓存

                本地缓存可以让静态资源加载更快,客户端发起请求后,静态资源可以直接从客户端获取,不需要向服务器发起请求。而这,需要设置服务器。 

        本地缓存有强缓存协商缓存两种形式。

        强缓存:浏览器在加载资源时,根据请求头中的expires或cache-control判断是否命中客户端缓存。若命中,则直接从缓存中提取,不会发起请求。

expires:指定资源的过期时间。过期时间以内,该资源可以被缓存使用。

                但是他是服务器时间,若服务器时间与本地时间不一致,可能会影响缓存命中的结果。

cache-control : 可选值如下:

        no-cache : 要先和服务器确定资源是否有更新,在进行判断。如果资源没有发生变化,则直接使用缓存好的资源。也就是说 没有强缓存但是会有协商缓存。

        no-store : 不使用任何缓存,每次请求都是从服务器直接获取资源。

        private : 设置了该字段的资源只能被用户浏览器缓存,不允许任何代理服务器缓存。在实际开发中对于含有用户信息的HTML都要设置这个字段,避免代理服务器(CDN)缓存。

        max-age : 设置缓存的最大有效期。

        协商缓存:浏览器会先发送一个请求到服务器,通过last-modifed 和 etag 验证资源是否命中客户端缓存。如果命中,服务器会将这个请求返回【返回304状态码】,但不会返回资源的数据,依然从缓存中读取资源。

2.1.2 DNS查询

        原因:每一次DNS查询都要经历从客户端到移动信号塔,再到认证DNS服务器的过程,这中间需要很长时间。

        方法:让DNS走缓存,幸好浏览器提供了DNS预处理的接口,我们可以在打开浏览器或者webView的同时就进行配置。

<mate http-equiv="x-dns-prefetch-control" content="on"> 开启预解析

<link rel="dns-perfetch" href="https://s.google.com/"> 强制对 https://s.google.com 域名进行预解析

注意!!! 

DNS预处理:是处理其他域名下的资源,不是浏览器输入的URL进行域名解析的过程。 

2.1.3 HTTP请求

        最大的瓶颈点:请求阻塞。

  请求阻塞 :浏览器为保证访问速度,会默认对同一域名下的资源保持一定的连接数,请求过多时就会阻塞。

  浏览器同一域名的连接限制:6个,只能六个并发。其余的得等最先返回的请求后,才能做下一次请求。

        域名规划很重要!!!最关键是首屏需要用到哪些域名!!

        域名散列:通过不同的域名,增加请求并行连接数。

        将静态服务器地址 pic.google.com,做成支持 pic0-5 的六个域名,每次请求时随机选一个域名地址进行请求。因为有六个域名同时可用,最多可以并行36个连接。当然,域名也不是越多越好,太分散的话 还会涉及多域名无法缓存静态资源的问题。

2.2 服务器处理数据请求阶段

        数据是否做了缓存处理、是否做了Gzip压缩、是否有重定向 

 2.2.1 数据缓存

原因:每请求一次数据接口,需要从客户端到服务器再到更后端的数据存储层,一层一层返回数据,最后再给到客户端,耗时很长。

        1. 借助 service worker 的数据接口缓存

service Worker 是浏览器的一个高级属性,本质上是一个请求代理层。

它存在的目的就是拦截和处理网络数据请求。 

        2. 借助本地缓存的接口缓存

在一些对数据时效性要求不高【不常变化】的页面,第一次请求到数据后,将数据本地存储,下一次请求时,先去缓存中取数据,没有再向服务器发起请求。

        3. CDN(虚拟服务器)

通过在网络各处放置节点服务器构造一个智能虚拟网络,将用户的请求导向离用户最近的服务器节点上。 

2.2.2 页面重定向

重定向 是指网站资源移动到其他位置后,用户访问站点,程序自动将用户请求转移到另一个页面的过程。

原因:重定向会引发新的DNS查询,导致新的TCP三次握手、TLS协商以及新的HTTP请求,而这会导致请求过程需要更多的时间,进而影响前端性能。

可能出现重定向的情况: 

        1. 服务端发挥的302重定向

        2. meta标签实现的重定向

        3. 前端js通过 window.location实现的重定向 

2.3 页面解析和渲染阶段的瓶颈期

页面解析: HTML 解析器把页面内容转换为DOM树和CSSOM树的过程。

        DOM树 :文档解析模型,它描述了标签之间的层次和结构。

        CSSOM树:CSS对象模型,主要描述样式集之间的层次和结构。

渲染:主线程会计算DOM树最终样式,生成布局树。布局树会纪录参与页面布局的节点和样式。

绘制:把各个节点绘制到屏幕的过程。绘制结构以层的形式保存。当文档的各个部分以不同的层绘制时,相互重叠的部分,就必须就行合成。

2.3.1 DOM树构建过程

        1. HTML标签不满足语义化,浏览器需要花费更多的时间去解析DOM的含义。

        2. HTML标签出错,浏览器会进行语法纠错

       1.  HTML标签不完整。 <br /> 少写结束符 / 

       2. 表格嵌套不标准

       3. 标签层次结构复杂

        3. DOM节点数量多。构建DOM树的时间就长,拖慢页面展示速度。

        4. 文档包含<script>标签时。

无论是DOM树还是CSSOM树都可以被JavaScript所访问并修改。因此一旦页面解析遇到<script>标签,DOM的构造过程就会暂停,等待服务器请求脚本。 

        解决方案:延迟加载外部脚本。

1. 使用 defer 或者 async

        区别:defer是HTML解析与js脚本加载同步进行,但js脚本执行是在HTML解析完成后,不会造成页面阻塞。async是HTML解析与js脚本加载同时进行,但脚本加载完成后立即执行,这时若HTML未解析完成,则仍会造成页面阻塞。

2. 动态创建DOM

        在HTML加载完成后,再动态的创建script标签来引入js脚本

3. 使用setTimeout定时器x 

2.3.2 CSSOM树生成阶段

2.3.3 重排和重绘

重排(回流): 当布局树中的部分或全部元素的尺寸、结构或者属性发生变化时,浏览器会重新渲染部分或全部文档的过程。(会导致周围的DOM元素重新排列)

重绘:当页面中某些元素的样式进行变化,但是不影响周围元素在文档流中的位置时,浏览器就会对元素进行重新绘制的过程。

3. 首屏时间采集

3.1 手动采集

        一般是通过埋点的方式进行。

在页面开始的地方打上 fmp.start ,首屏结束的事件 打上 fmp.end 。

商品详情页:在用户主要关注的商品信息加载完成后打上点

直播页:在直播框的结束位置打上点

         优点:

                1. 兼容性强,可以随情况变动而修改;

                2. 去中心化,各个业务负责自己的页面打点;

                3. 有问题业务同学可随时排查

        缺点:

                1. 手动采集代码会和业务逻辑代码严重耦合

                2. 覆盖率不足,一旦业务忙起来,性能优化方案就得延迟

                3. 结果可能不准确,因为每个人对首屏的理解不同,导致打错点或者忘记打点。

3.2 自动化采集

        引入一段通用化代码来做首屏时间采集。除了必要配置外,无需做其他操作。

        优点:独立性更强,接入过程更加自动化。

        缺点:有些个性化需求无法满足。

3.2.1 单页面应用的首屏时间 

        1. 用户请求一个页面时,会先加载index.html,加载完成后就会触发DOMComtentLoaded和load。【此时页面只是空白页,并没有完成渲染。 】

        2. 页面会加载脚本资源并通过axios异步请求数据。使用数据渲染页面主题部分,这个时候首屏才渲染完成。

可以使用 mutationObserver 采集首屏时间

3.2.2 pc端的白屏时间采集

pc端的页面加载过程: 
        1. 客户端发起请求

        2. 下载HTML及JS/CSS资源

        3. 解析JS执行

        4. JS请求数据

        5. 客户端解析DOM并渲染

        6. 下载渲染图片

        7. 完成整体渲染

其中,客户端解析DOM并渲染之前的时间都算是白屏时间

白屏时间  = 页面开始展示的时间 - 发起请求的时间

白屏时间 FP = domLOading - navigationSrart

3.2.3 卡顿的时间采集 

在浏览器上我们没办法取到单帧渲染耗时的接口,所以只能用FPS来计算 

不卡顿:连续三帧不低于20FPS,且保持恒定 

4. 优化方案

4.1 首屏秒开

4.1.1 懒加载 

在长页面加载过程中,先加载关键内容,延迟加载非关键内容。 

先根据手机的可视窗口计算需要的数据,超出首屏的内容,可以在下拉或者滚动时再发起加载。

若首屏中图片较多,也可以使用懒加载。 估算当前手机首屏展示所需的最大数据,先请求,在可视化中展示,其他位置用占位符填充。滑到目标区域位置后,才使用真实的图片填充。

4.1.2 接口缓存

4.1.3 静态资源缓存

        1. 静态资源长期不变的 -- 强缓存

设置 cache-control:max-age=31536000  一年内有效 

        2. 静态资源频繁改变的 -- 协商缓存

在初次请求资源时,设置Etag并返回200 的状态码,之后请求时带上 if-none-match 字段来询问服务器当前版本是否可用。  

4.1.4 离线化 

线上实时变动的资源数据静态化到本地,访问时走的本地文件。 

适合首页不用登陆的情况,能够支持SEO 

使用 prerenderSpaPlugin 插件

4.1.5 并行化

解决请求阻塞,进而减少首屏时间。 

 HTTP2.0 多路复用

4.2 白屏优化

4.2.1 DNS预解析 

【2.1.2】 

4.2.2 首字符展示优化 

         采用骨架屏 

4.3 卡顿治理

        1. 先定位问题,若是数据请求的问题,则需要找后台配合

        2. 若为前端问题,则可能是 浏览器的主线程与合成线程调度不合理或者是计算耗时

4.3.1 浏览器的主线程与合成线程调度不合理 

主线程 主要负责运行 JavaScript,计算css样式,元素布局,然后交给合成线程

合成线程主要负责绘制

当使用height、width、margin、padding等作为transition值时,会让主线程的压力变大。

可以使用tranform来代替直接设置margin等操作

margin-left:10px --》 margin-left:0  主线程经过margin-left:10px margin-left:9px  margin-left:8px ......margin-left:0,每次主线程渲染样式后,合成线程都需要绘制到GPU再渲染到屏幕上。

优化:可以使用 transform:tranlate(10px,0)-->transform:tranlate(0,0)

4.3.2 计算耗时 

        解决方案:空间换时间  时间换空间 

        1. 空间换时间

        增删DOM元素的过程,最好先在documentFragment 上操作,而不是直接在DOM上进行操作。

        2. 时间换空间

        将一个复杂的操作细分成一个队列,然后通过多次操作解决复杂问题。 

文章参考:

【前端性能优化方法与实战】

  • 25
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值