# H5 优化
# 网络层优化
# DNS 处理:增加 dns-prefetch
浏览器对网站第一次的域名 DNS 解析查找流程依次为:浏览器缓存 >> 系统缓存 >> 路由器缓存 >> ISP DNS 缓存 >> 递归搜索
- 用 meta 信息来告知浏览器,当前页面要做 DNS 预解析
<meta http-equiv="x-dns-prefetch-control" content="on" />
- 在页面 header 中使用 link 标签来强制对 DNS 预解析
<link rel="dns-prefetch" href="//topicstatic.vivo.com.cn" />
# CDN 分发优化
静态资源使用 CDN
- 通过 CDN 向用户分发传输相关库的静态资源文件,可以降低我们自身服务器的请求压力。
- 大多数 CDN 在全球都有服务器,所以 CDN 上的服务器在地理位置上可能比你自己的服务器更接近你的用户。用户直接访问边缘缓存,极大地提升页面资源的响应速度。
- 不缓存 HTML 入口文件,只缓存 js、css 的策略,避免资源不更新的同时,加快了专题资源的获取速度。
不缓存 HTML 入口文件的目的是防止客户端缓存策略,导致主入口资源不更新,导致线上升级失败。
# HTTP/2
多路复用代替原有的序列以及阻塞机制,使得多个资源可以在一个连接中并行下载,不受浏览器同一域名资源请求限制,提升整站的资源加载速度。
# 资源优化
# 图片懒加载
懒加载的一般形式表现为:
- 打开首页,滑动页面
- 懒加载图片展示默认图
- 默认图替换为真实图片
方案:选择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()动态加载