23 如何加快页面显示和相应

Posted by CodingWithAlice on April 18, 2021

23 如何加快页面显示和相应

页面优化 – 就是让页面更快得显示和响应

由于页面在不同阶段的关注点不同,可以划分为几个阶段

  • 加载 阶段:从发出请求到渲染出完整页面的过程,影响因素主要是 网络和 JS 脚本
  • 交互 阶段:从页面加载完成到用户交互的过程,影响因素主要是 JS 脚本
  • 关闭 阶段:用户发出关闭指令后页面所做的 清理操作

加载阶段

加载阶段的渲染流水线如下图:

image-20210418122243412

分析:

​ 并不是所有资源都会阻塞页面的首次渲染(图片、音频、视频等),而 JS、CSS和首次请求的HTML资源 是会阻塞首次渲染的 – 关键资源

细化: 通过关键资源,可以细化出三个影响首次渲染的 核心因素

  • 1、关键资源个数
    • 可以将 JS 和 CSS 写成内联 - 减少 HTTP 请求次数
    • 若 JS 没有操作 DOM,可以添加 defer/sync 属性 –> 转换为非关键资源
    • 若 CSS 不是构建页面之前需要加载的,可以给 link 属性添加标志 –> 转换为非关键资源
  • 2、关键资源大小
    • 压缩 CSS 和 JavaScript 资源
    • 移除 HTML、CSS、JS 文件中一些注释内容
    • 取消 CSS 或者 JS 中关键资源
  • 3、请求关键资源需要多少RTT(Round Trip Time)
    • 减少关键资源的个数和减少关键资源的大小
    • 可以使用 CDN 来减少每次 RTT 时长

RTT 计算方式:

  • HTML 资源(上图6KB) - 1 RTT
  • 由于渲染引擎有一个 预解析线程,接收到 HTML 后快速扫描是否有关键资源,发起的 JS 和 CSS 请求可以认为是同时发起的,请求时间是重叠的,计算 RTT 时,只需要计算较大的文件(CSS - 9KB - 1RTT);也就是上图资源只需要2个RTT;

什么事 RTT

在这里插入图片描述

  • RTT - 表示 从发送端发送数据开始,到发送端收到来自接收端的确认,总共经历的时延 – 例如0.1M的文件,就是8个包,即8个 RTT

    img

  • TCP 协议传输一个文件时,数据并不是一次传输到服务端的,而是需要拆分成一个个数据包【一般14KB】来回多次进行传输的。

交互阶段

交互阶段的渲染流水线如下:

image-20210418122402135

  • 分析:

    交互阶段的优化 –> 也就是 渲染进程渲染帧的速度 优化 –> 也就是明白渲染引擎如何渲染帧

  • 细化:

    交互阶段,没有加载关键资源和构建DOM、CSSOM的过程,一般 由JS触发 交互动画,一般三种方式:重排、重绘、合成

  • 帧的生成速度及优化方案

    • 1、减少 JavaScript 脚本执行时间,两种策略

      • 1⃣️ 将一次执行的函数 分解 为多个任务,使得每次的执行时间不要过久
      • 2⃣️ 采用 Web Workers(类似主线程以外的线程,可以执行 JS 脚本,但是没有 DOM、CSSOM 环境,即 JS 不能访问DOM),可以把一些和 DOM 操作无关且耗时的任务放到 Web Workers 中去执行
    • 2、避免强制同步布局

      • 正常布局:通过 DOM 接口执行添加元素或者删除元素等操作后,是需要 重新计算样式和布局 的,不过正常情况下这些操作都是在另外的任务中 异步完成 的,这样做是为了避免当前的任务占用太长的主线程时间。
      • 强制同步布局:指 JS 强制将计算样式和布局操作提前到当前的任务中。(白话一点说就是,通过JS改变元素高度,本来应该异步计算,重新布局的;但是改变完元素后,就马上通过 JS 获取改变后的高度,导致渲染引擎只能强制执行一次布局【同步】来获取高度)
      • 解决策略:可以在修改 DOM 之前查询相关值
    • 3、避免布局抖动

      • 指在一次 JS 执行过程中,多次执行强制布局和抖动操作(例如在一个 for 循环语句里面不断读取属性值,每次读取属性值之前都要进行计算样式和布局

        image-20210418122610962

      • 解决策略:尽量不要在修改 DOM 结构时再去查询一些相关值

    • 4、合理利用 CSS 合成动画

      合成动画是直接在 合成线程 上执行的,和主线程无关,可以多加利用

      如果能提前知道对某个元素 执行动画操作,那就最好将其标记为 will-change,这是告诉渲染引擎需要将该元素单独生成一个图层

    • 5、避免频繁的垃圾回收 JS 使用了自动垃圾回收机制:如果在一些函数中 频繁创建临时对象,那么垃圾回收器也会频繁地去执行垃圾回收策略 –> 当垃圾回收操作发生时,就会 占用主线程,从而影响到其他任务的执行,严重的话还会让用户产生掉帧、不流畅的感觉