# H5 优化

# 网络层优化

# DNS 处理:增加 dns-prefetch

浏览器对网站第一次的域名 DNS 解析查找流程依次为:浏览器缓存 >> 系统缓存 >> 路由器缓存 >> ISP DNS 缓存 >> 递归搜索

  1. 用 meta 信息来告知浏览器,当前页面要做 DNS 预解析
<meta http-equiv="x-dns-prefetch-control" content="on" />
  1. 在页面 header 中使用 link 标签来强制对 DNS 预解析
<link rel="dns-prefetch" href="//topicstatic.vivo.com.cn" />

# CDN 分发优化

静态资源使用 CDN

  • 通过 CDN 向用户分发传输相关库的静态资源文件,可以降低我们自身服务器的请求压力。
  • 大多数 CDN 在全球都有服务器,所以 CDN 上的服务器在地理位置上可能比你自己的服务器更接近你的用户。用户直接访问边缘缓存,极大地提升页面资源的响应速度。
  • 不缓存 HTML 入口文件,只缓存 js、css 的策略,避免资源不更新的同时,加快了专题资源的获取速度。

不缓存 HTML 入口文件的目的是防止客户端缓存策略,导致主入口资源不更新,导致线上升级失败。

# HTTP/2

多路复用代替原有的序列以及阻塞机制,使得多个资源可以在一个连接中并行下载,不受浏览器同一域名资源请求限制,提升整站的资源加载速度。

# 资源优化

# 图片懒加载

懒加载的一般形式表现为:

  1. 打开首页,滑动页面
  2. 懒加载图片展示默认图
  3. 默认图替换为真实图片

方案:选择vue-lazyload去支撑位组件的图片来加载

<template>
  <div>
    <img v-lazy="imgUrl" />
    <div v-lazy:background-image="imgUrl"></div>

    <!-- with customer error and loading -->
    <img v-lazy="imgObj" />
    <div v-lazy:background-image="imgObj"></div>

    <!-- Customer scrollable element -->
    <img v-lazy.container="imgUrl" />
    <div v-lazy:background-image.container="img"></div>

    <!-- srcset -->
    <img
      v-lazy="'img.400px.jpg'"
      data-srcset="img.400px.jpg 400w, img.800px.jpg 800w, img.1200px.jpg 1200w"
    />
    <img
      v-lazy="imgUrl"
      :data-srcset="imgUrl' + '?size=400 400w, ' + imgUrl + ' ?size=800 800w, ' + imgUrl +'/1200.jpg 1200w'"
    />
  </div>
</template>
<script>
  export default {
    data() {
      return {
        imgObj: {
          src: 'http://xx.com/logo.png',
          error: 'http://xx.com/error.png',
          loading: 'http://xx.com/loading-spin.svg'
        },
        imgUrl: 'http://xx.com/logo.png' // String
      }
    }
  }
</script>

# 图片压缩

使用 webp 压缩,基于 Webp 的图片高效加载方案 (opens new window)

# 渲染执行优化

# 避免重排

会导致浏览器重排的动作:

(1)增加或删除 DOM 节点;

(2)display:none(重排并重绘);

​ visibility:hidden(重绘);

(3)移动页面中的元素;

(4)改变元素尺寸(宽、高、内外边距、边框等);

(5)用户改变窗口大小,滚动页面等;

(6)页面初始渲染;

(7)改变元素内容(文本或图片等)。

# 善用 Vue 生命周期

在 mounted 阶段,浏览器已经完成 dom 与 css 规则树的 render,并完成 render tree 布局,这时候再去发送数据请求,会拉长请求时间和渲染周期,所以建议在 beforeCreate 中执行,以此达到预渲染和请求的并行进行。

export default {
  beforeCreate() {
    fetch({
      url: topicUrl,
      params: {
        //...
      }
    }).then(res => {
      //数据处理
      //...
    })
  },
  mounted() {
    // global listener
    window.addEventListener('xxx')
    // get dom element by refs
    this.$refs.xxx
    // get dom element use native api
    document.querySelector
  }
}

我们将初始化数据的动作放在 beforeCreate 阶段,并将对 dom 的操作和监听挂载在 mounted 中。

# 减少白屏时间

白屏时间是指浏览器从响应用户输入网址地址,到浏览器开始显示内容的时间。

采用如下方式去减少白屏时间:

  • 骨架屏,html 直接渲染过渡效果
  • 改造第三方 JS 引入顺序
  • 使用 SplitChunksPlugin 拆分公共代码;
  • 使用动态 import,切分页面代码,减小首屏 JS 体积

# 性能数据收集

# 白屏时间

白屏时间 = 开始渲染时间(首字节时间+HTML 下载完成时间)= responseStart - navigationStart

首次渲染时长 = 全部事件注册时长 = loadEventEnd - navigationStart

页面绘制时间=获取数据到加载结束 = loadEventEnd - fetchEnd(自行记录)

# 上报方法

navigator.sendBeacon() 方法可用于通过HTTP (opens new window)将少量数据异步传输到 Web 服务器。

这个方法主要用于满足统计和诊断代码的需要,发送代码通常尝试在卸载(unload)文档之前向 web 服务器发送数据。

function stat() {
  navigator.sendBeacon('/path', analyticsData)
}

sendBeacon 发出的是异步请求,请求作为浏览器任务执行,与当前页面脱钩。因此该方法不会阻塞页面加载流程,也不会延迟页面加载。

# H5 加载慢

尽量避免使用效大的第三方库, 控制整体 js 的大小, 控制首屏加载用到的 js 大小 (建议整体不超过 300k), 首屏以外的可以使用 import()动态加载