web性能优化
# show_page
通常来讲,前端性能优化是指:从用户开始访问网站到整个页面完整地展现出来的过程中, 通过各种优化策略和优化方法,让页面加载得更快,让用户的操作相应更及时,给用户更好的使用体验。
# 图片优化的常见方法
# 1、用工具压缩图片
压缩 PNG 图片:
- 工具:node-pngquant-native (opens new window)
- 介绍:跨平台、压缩比特别高,压缩png24非常好。
安装方法:
npm install node-pngquant-native
压缩 JPEG 图片:
- 工具:jpegtran (opens new window)
- 官网:https://www.npmjs.com/package/jpegtran (opens new window)
- 介绍:跨平台,但压缩的比率只有80-90%。
安装方法:
npm install –g jpegtran
使用方法:
jpegtran -copy none -optimize -outfile output_file.jpg input_file.jpg
压缩 GIF 图:
- 工具:Gifsicle
- 官网(含安装方法):https://www.lcdf.org/gifsicle/ (opens new window)
- 介绍:Gifsicle 通过改变每帧比例,减小 gif文件大小,同时可以使用透明来达到更小的文件大小,是目前公认的最好的解决方案。
使用方法:
# 压缩命令。注意,这里是将压缩级别设置为3。如果将压缩级别设置为1或者2,则基本不压缩。
gifsicle --optimize=3 -o out_file.gif in_file.gif
# 裁掉透明部分
gifsicle --optimize=3 --crop-transparency -o out_file.gif in_file.gif
# 2、将图片尺寸跟随网络环境进行变化
具体方案:不同网络环境(Wifi/4G/3G)下,加载不同尺寸和像素的图片,通过在图片 URL 中添加参数来改变。
图片 url 举例1:(图片的原始url链接)
https://img12.360buyimg.com/img/s3866x3866_jfs/t1/149913/14/18648/719436/5fd8b9b5Eb697b825/7c23f3028aff8e2b.jpg
图片 url 举例2:(通过图片的url参数,将这张图的尺寸设置为200px)
https://img12.360buyimg.com/img/s200x200_jfs/t1/149913/14/18648/719436/5fd8b9b5Eb697b825/7c23f3028aff8e2b.jpg
# 3、响应式图片
方法1:通过 JavaScript 绑定事件,检测窗口大小,以此设置图片大小。
方法2:CSS媒体查询。
代码举例:(在 640px的窗口大小里,设置图片的尺寸为640px)
@media screen and (max-width:640px) {
my_image{
width:640px;
}
}
方法3:img标签的 srcset
属性。这个是 H5的新特性。
代码举例:
<img srcset="img-320w.jpg, img-640w.jpg 2x, img-960w.jpg 3x" src=“img-960w.jpg”
alt=“img”> (x 描述符:表示图像的设备像素)
# 4、逐步加载图像:lazyload、LQIP、LQIP
方法1、使用统一占位符。俗称图片的懒加载(lazyload)
。
方法2、使用 LQIP 的图片加载方式。也就是说,在大图没有完全加载出来的情况下,先这张图对应的的低质量图片进行占位。
LQIP(Low Quality Image Placeholders):低质量图像占位符。这种技术背后的想法是,在网络环境较差的情况下,你可以尽快向用户展示完全可用的网页,为他们提供更好的体验。即使在更好的网络连接上,这仍然为用户提供了更快的可用页面,并且改善了体验。
- 安装 LQIP 工具:
npm install lqip
- GitHub源码:https://github.com/zouhir/lqip-loader (opens new window)
代码举例:(将目标图片转换为 LQIP 形式的图)
const lqip = require('lqip');
//文件路径
const file = './in.png';
//将输入的图片转为base64
lqip.base64(file).then(res => {
// 色值
console.log(res);
});
lqip.palette(file).then(res => {
//这里输出的是base64的图片地址
console.log(res);
});
另外,我们还可以使用 SQIP 的图片加载方式。
SQIP(SVG Quality Image Placeholders): SVG 格式的图像占位符。
- 安装 SQIP 工具:
npm install sqip
- GitHub 源码:https://github.com/axe312ger/sqip (opens new window)
代码举例:(将目标图片转换为 SQIP 形式的图)
const sqip = require('sqip');
const result = sqip({
filename: './input_file.png',
numberOfPrimitives: 10 //可根据不同应用场景设置大小
});
console.log(result.final_svg);
# 5、雪碧图(Image spriting)
雪碧图是比较常见的图片优化方式,也就是把多张小图合并成一张大图。这样的话,就只需做一次网络请求,减少图片的 http 请求次数。
读者们可以自行查阅。
# 6、有些场景下,并不需要图片文件
有些场景下,并不需要图片,我们可以用其他的方式来代替图片。
举例:
- Web Font 代替图片
- 使用 Data URI 代替图片。base64就是属于 Data URI的方式。
# 7、在服务器端进行图片自动优化
图片服务器自动化优化是可以在图片 URL 链接上增加不同特殊参数,服务器自动化生成。通过这些参数,可以设置图片的不同格式、大小、质量。
常见处理方式:
- 图片裁剪:按长边、短边、填充、拉伸等缩放。
- 图片格式转换:支持 JPG,GIF,PNG,WebP 等,支持不同的图片压缩率。
- 图片处理:添加图片水印、高斯模糊、重心处理、裁剪边框等。
- AI 能力:鉴黄、涉政、智能抠图、智能排版、智能配色、智能合成等 AI 功能。
图片举例:
比如JD公司的图片链接,就会在服务器端做优化处理。通过修改图片链接中的参数,就能自动达到相应的优化效果。
原始图片链接:
https://img12.360buyimg.com/img/s3866x3866_jfs/t1/149913/14/18648/719436/5fd8b9b5Eb697b825/7c23f3028aff8e2b.jpg
将图片压缩为 200*150:
https://img12.360buyimg.com/img/s200x200_jfs/t1/149913/14/18648/719436/5fd8b9b5Eb697b825/7c23f3028aff8e2b.jpg
将图片转换为 webp 格式:
https://img12.360buyimg.com/img/s200x200_jfs/t1/149913/14/18648/719436/5fd8b9b5Eb697b825/7c23f3028aff8e2b.webp
将图片质量压缩至10%:
https://img12.360buyimg.com/img/s3866x3866_jfs/t1/149913/14/18648/719436/5fd8b9b5Eb697b825/7c23f3028aff8e2b.jpg.q10
# HTML优化
# 1、精简 HTML 代码
- 减少 HTML 的嵌套。
- 减少 DOM 节点数。
- 减少无语义代码(比如: 消除浮动,其实可以用css来处理)。
- 删除 http 或者 https:如果URL的协议头和当前页面的协议头一致的,或者此 URL 在多个协议头都是可用的,则可以考虑删除协议头。
- 删除多余的空格、换行符、缩进和不必要的注释。
- 省略冗余标签和属性。
- 使用相对路径的 URL。
# 2、文件放在合适位置
- CSS 样式文件链接尽量放在页面头部。
CSS 加载不会阻塞 DOM tree 解析,但是会阻塞 DOM Tree 渲染,也会阻塞后面 JS 执行。
任何 body 元素之前,可以确保在文档部分中解析了所有 CSS 样式(内联和外联),从而减少了浏览器必须重排文档的次数。
如果放置页面底部,就要等待最后一个 CSS 文件下载完成,此时会出现"白屏",影响用户体验。
- JS 引用放在 HTML 底部
防止 JS 在加载、解析、执行时,阻塞了页面后续元素的正常渲染。
# 4、增强用户体验
- 设置 favicon.ico
网站如果不设置 favicon.ico,控制台会报错。另外页面加载过程中如果没有图标,则会出现 loading 过程,也不利于记忆网站品牌,建议统一添加。
- 增加首屏必要的 CSS 和 JS
页面如果需要等待所的依赖的 JS 和 CSS 加载完成才显示,则在渲染过程中页面会一直显示空白,影响用户体验,建议在首屏增加必要的 CSS 和 JS,比如页面框架背景图片或者loading 图标,内联在 HTML 页面中。这样做,首屏能快速显示出来,缓解用户焦虑。现在很多网页在初始化的时候,流行做骨架屏,小伙伴们也可以研究下。
# CSS优化
# 1、提升 CSS 渲染性能
- 谨慎使用 expensive 属性,这类属性比较耗浏览器的性能。比如:
nth-child
伪类;position: fixed
定位。 - 尽量减少样式的层级数。
比如:div ul li span i {color: blue;}
这样的层级就太深了。建议给 i 标签设置 class属性,然后通过class直接设置样式属性,可以提升浏览器的查询效率。
- 尽量避免使用占用过多 CPU 和内存的属性。比如:
text-indnt:-99999px
。 - 尽量少使用耗电量大的属性。比如:CSS3 3D transforms、CSS3 transitions、Opacity 这样的属性会消耗GPU。
# 2、合适使用 CSS 选择器
- 尽量避免使用 CSS 表达式。
比如 background-color: expression( (new Date()).getHours()%2 ? "#FFF" : "#000" );
这个属性的意思是,每间隔两小时,改变白景色。
- 尽量避免使用通配选择器。
比如 body > a {font-weight:blod;}
这样的属性,可能会把 body 里所有的标签遍历一遍,才找到 a 标签,比较耗时。
- 尽量避免类正则的属性选择器:
*=, |=, ^=, $=
# 3、提升 CSS 文件加载性能
- 使用外链的 CSS。
我们知道,内联的 css 是在html 内部写的。相比之下,外链的 CSS文件是放在CDN上的,可以缓存,既能减少 html 页面的体积大小,也能利用缓存减少资源的请求。
- 尽量避免使用 @import 方法
整个CSS加载完成后,浏览器会把 import 中所有依赖的文件全部加载完成后,浏览器才会接着往下渲染。这个过程会阻塞CSS文件的加载过程。
# 4、精简 CSS 代码
- 使用缩写语句
- 删除不必要的零。比如 0.2 可以写成 .2
- 删除不必要的单位,比如 0px 可以写成 0
- 删除过多的空格;注释言简意赅
- 尽量减少样式表的大小
当然,很多地方可以在编译时,通过压缩工具来处理;但是我们在写代码时,也应该有良好的编码习惯。
# 5、合理使用 Web Fonts
- 将字体文件部署在 CDN 上。
- 或者将字体以 base64 形式保存在 CSS 中并通过 localStorage 进行缓存
- Google 字体库因为某些不可抗拒原因,应该使用国内托管服务
# 6、CSS 动画优化
- 尽量避免同时出现过多动画。
- 延迟动画初始化:让其他的重要的CSS样式优先渲染。
- 结合 SVG。
# JavaScript 总体优化
# 提升 JavaScript 文件加载性能
加载元素的顺序 CSS 文件放在 <head>
里, JavaScript 文件放在 <body>
里。
# JavaScript 变量和函数优化
- 尽量使用 id 选择器
- 尽量避免使用 eval
- JavaScript 函数尽可能保持简洁
- 使用事件节流函数
- 使用事件委托
# JavaScript 动画优化
- 避免添加大量 JavaScript 动画
- 尽量使用 CSS3 动画
- 尽量使用 Canvas 动画
- 合理使用 requestAnimationFrame 动画代替 setTimeout、setInterval
- requestAnimationFrame可以在正确的时间进行渲染,setTimeout(callback)和setInterval(callback)无法保证 callback 回调函数的执行时机。
# 合理使用缓存
- 合理缓存 DOM 对象
- 缓存列表长度
- 使用可缓存的 Ajax
# JavaScript 缓存优化
# Cookie
通常由浏览器存储,然后将 Cookie 与每个后续请求一起发送到同一服务器。收到HTTP 请求时,服务器可以发送带有 Cookie 的 header 头。可以给 Cookie 设置有效时间。
应用:
- 会话管理:登录名,购物车商品,游戏得分或服务器应要记录的其他任何内容
- 个性化:用户首选项,主题或其他设置
- 跟踪:记录和分析用户行为,比如visitkey
# sessionStorage
创建一个本地存储的键/值对。
应用:
- 缓存。
- 页面应用页面之间传值。
# LocalStorage
本地存储。
应用于:
- 缓存静态文件内容 JavaScript /CSS(比如百度M站首页)
- 缓存不常变更的 API 接口数据
- 储存地理位置信息
- 浏览在页面的具体位置
# IndexedDB
索引数据库。
应用:
- 客户端存储大量结构化数据
- 没有网络连接的情况下使用(比如 Google Doc、石墨文档)
- 将冗余、很少修改、但经常访问的数据,以避免随时从服务器获取数据
# JavaScript 模块化加载方案和选型
- CommonJS
旨在 Web 浏览器之外为 JavaScript 建立模块生态系统。Node.js 模块化方案受 CommonJS。
- AMD (Asynchronous Module Definition)(异步模块定义)规范。
RequireJS 模块化加载器:基于 AMD API 实现。
- CMD( Common Module Definition)(通用模块定义)规范。
SeaJS 模块化加载器:遵循 CMD API 编写。
- ES6 import。
# 减少回流和重绘重要举措
# CSS
- 避免过多样式嵌套
- 避免使用 CSS 表达式
- 使用绝对定位,可以让动画元素脱离文档流
- 避免使用 table 布局
- 尽量不使用 float 布局
- 图片最好设置好 width 和 height
- 尽量简化浏览器不必要的任务,减少页面重新布局
- 使用 Viewport 设置屏幕缩放级别
- 避免频繁设置样式,最好把新 style 属性设置完成后,进行一次性更改
- 避免使用引起回流/重绘的属性,最好把相应变量缓存起来
# JavaScript
- 最小化回流和重排:为了减少回流发生次数,避免频繁或操作 DOM,可以合并多次对 DOM 修改,然后一次性批量处理。
- 控制绘制过程和绘制区域:绘制过程开销比较大的属性设置应该尽量避免减少使用;同时,减少绘制区域范围。
# DOM 编程优化
# 控制 DOM 大小
众所周知,页面交互卡顿和流畅度很大一部分原因就是页面有大量 DOM 元素。想象一下,从一个上万节点的 DOM 树上,使用 querySelectorAll 或 getElementByTagName 方法查找某一个节点,是非常耗时的。另外元素绑定事件,事件冒泡和事件捕获的执行也会相对耗时。
通常控制 DOM 大小的技巧包括:
- 合理的业务逻辑
- 延迟加载即将呈现的内容
# 简化 DOM 操作
对DOM节点的操作统一处理后,再统一插入到 DOM Tree中。
可以使用 fragment,尽量不在页面 DOM Tree 里直接操作。
现在流行的框架 Angular、React、Vue 都在使用虚拟 DOM 技术,通过 diff 算法简化和减少 DOM 操作。
# 静态文件压缩工具介绍
HTML 压缩工具:
CSS 压缩工具:
JavaScript 压缩工具:
- uglify-js:https://www.npmjs.com/package/uglify-js (opens new window)
- 使用方法:uglifyjs in.js -o out.js
# 静态文件打包优化方案
- 公共组件拆分
- 压缩: JavaScript /CSS/图片
- 合并: JavaScript /CSS 文件合并,CSS Sprite
- Combo: JavaScript /CSS 文件
# 静态文件版本号更新策略
缓存更新:CDN 或 ng 后台刷新文件路径,更新文件header头。
文件 name.v1-v100.js:
- 大功能迭代每次新增一个大版本,比如由 v1 到 v2
- 小功能迭代新增加 0.0.1 或者 0.1.0,比如从 v1.0.0 至 v1.0.1
- 年末 ng 统一配置所有版本 302 至最新版
时间戳.文件 name.js:以每次上线时间点做差异。
hash.文件。以文件内容 hash 值做 key。
# 前端构建工具介绍和选型建议
# 常用构建工具
- Gulp:通过流(Stream)来简化多个任务间的配置和输出,配置代码相对较少。
- Webpack:预编译,中间文件在内存中处理,支持多种模块化,配置相对很简单。
- FIS
# webpack 打包优化
- 定位体积大的模块
- 删除没有使用的依赖
- 生产模式进行公共依赖包抽离
- 开发模式进行 DLL & DllReference 方式优化
# 浏览器渲染过程
- 浏览器解析 HTML,生成 DOM Tree(Parse HTML)。
- 浏览器解析 CSS,生成 CSSOM(CSS Object Model)Tree。
- JavaScript 会通过 DOM API 和 CSSOM API 来操作 DOM Tree 和 CSS Rule Tree,浏览器将 DOM Tree 和 CSSOM Tree 合成渲染树(Render Tree)。
- 布局(Layout):根据生成的 Render Tree,进行回流,以计算每个节点的几何信息(位置、大小、字体样式等等)。
- 绘制(Painting):根据渲染树和回流得到的几何信息,得到每个节点的绝对像素。
- 展示(Display):将像素发送给图形处理器(GPU),展示在页面上。
# 页面渲染技术方案总览
服务端渲染:
- 后端同步渲染、同构直出、BigPipe。
客户端渲染:
- JavaScript 渲染:静态化、前后端分离、单页面应用
- Web App:React、Vue、PWA
- Hybrid App:PhoneGap 、AppCan 等
- 跨平台开发:RN 、Flutter 、小程序等。
- 原生 App:iOS 、Android
建议:
- 依赖业务形式、依赖团队规模、依赖技术水平。
# 静态化技术方案
静态化是使动态化的网站生成静态 HTML 页面以供用户更好访问的技术,一般分为纯动态化和伪动态化。
技术优势:
- 提高了页面访问速度,降低了服务器的负担,因为访问页面时不需要每次去访问数据库。
- 提高网站内容被搜索引擎搜索到的几率,因为搜索引擎更喜欢静态页面。
- 网站更稳定,如果后端程序、数据库出现问题,会直接影响网站的正常访问,而静态化页面有缓存,更不容易出现问题。
技术不足:
- 服务器存储占用问题,因为页面量级在增加,要占用大量硬盘空间。
- 静态页面中的链接更新问题会有死链或者错误链接问题。
技术实现:
- 跑定时任务,将已有的动态内容进行重定,生成静态的 HTML 页面。
- 利用模板技术,将模板引擎中模板字符替换为从数据库字段中取出来的值, 同时生成 HTML 文件。
协作方式:
- 前端统一写好带有交互的完整静态页面。
- 后端拆分出静态页面文件,并嵌套在后端模板文件中。
选型建议:后端研发人员充分,又需要考虑用户体验、服务器负载的业务。
# 前后端分离技术与实现
前后端分离是指研发人员分离、业务代码分离、后端实现业务接口,前端渲染页面。
技术实现:
- 后端只负责功能接口实现,提供按照约定的数据格式并封装好的 API 接口。
- 前端负责业务具体实现,获取到 API 接口数据后,进行页面模板拼接和渲染,独立上线。
协作方式:
- 前端负责实现页面前端交互,根据后端 API 接口拼装前端模板。
- 后端专注于业务功能实现和 API 接口封装。
技术优势:
- 团队更加专注
- 提升了开发效率
- 增加代码可维护性
技术架构:
- 后端架构:Java、C++、PHP、 + Nginx,使用微服务(比如 Dubbo 等)等实现业务的解耦,所有的服务使用某种协议提供不同的服务(比如 JSF 等) 。
- 前端架构:使用 Angular、React、Vue 前端框架并部署页面至 CDN。
- 前端架构 2:使用 Angular、React、Vue 前端框架并部署在 Node Server。
技术不足:
- 因为前端需要负责一大部分业务逻辑实现,和服务端同步、静态化,需要前端人力非常多。
- 页面数据异步渲染,不利于 SEO,搜索引擎更喜欢纯静态页面。
选型建议:
- 这是大型互联网公司正在采用的开发模式,一句话,如果考虑用户体验,以及前端人力够用,就可以积极采用。
# 单页面应用技术方案
单页应用(single-page application,缩写 SPA),通过动态重写当前页面,来与用户交互,而非传统的从服务器重新加载整个新页面。这种方法在使用过程中不需要重新加载页面,避免了页面之间切换打断用户体验,使应用程序更像一个桌面应用程序。
技术优点:
- 不错的加载速度:用户往往感觉页面加载非常快,因为一进入页面就能看到页面元素;
- 良好的交互体验:进行局部渲染,避免不必要的页面间跳转和重复渲染;
- 前后端职责分离:前端进行页面交互逻辑,后端负责业务逻辑;
- 减轻服务器负载:服务器只处理数据接口输出,不用考虑页面模板渲染和 HTML 展示。
技术缺点:
- 开发成本相对较高
- 首次页面加载时间过多
- SEO 难度比较大
技术实现:
- 使用 React、Vue 框架可以很好的。
# BigPipe 简介和工作模式
BigPipe 通过将页面加载到称为 Pagelet 的小部件中,来加快页面渲染速度,并允许浏览器在 PHB 服务器呈现页面的同时,一直请求页面不同区块的结构,类似一个“流”传输管道。
技术实现:
- 浏览器从服务器请求页面。
- Server 迅速呈现一个包含 标记的页面框架,以及一个包含空 div 元素的主体,这些元素充当 Pagelet 的容器。由于该页面尚未完成,因此与浏览器的 HTTP 连接保持打开状态。
- 浏览器将开始下载 bigpipe.js 文件,然后它将开始呈现页面。
- PHP 服务器进程仍在执行,并且一次构建每个 Pagelet 。Pagelet 完成后,其结果将在
<script> BigPipe.onArrive(…)</ script>
标记内发送到浏览器。 - 浏览器将收到的 html 代码注入正确的位置。如果小页面需要任何 CSS 资源,则也将下载这些 CSS 资源。
- 接收完所有的页面集之后,浏览器将开始加载那些页面集所需的所有外部 JavaScript 文件。
- 下载 JavaScript 后,浏览器将执行所有内联 JavaScript。
# 同构直出技术方案
一套代码既可以在服务端运行又可以在客户端运行,这就是同构(Universal)。
技术优势:
- 性能: 降低首屏渲染时间
- SEO: 服务端渲染对搜索引擎的爬取有着天然的优势
- 兼容性: 有效规避客户端兼容性问题,比如白屏
- 代码同构:直接上线两个版本,利于灾备。
技术实现:
- next.js:服务器端渲染 React 组件框架(参考查看:https://nextjs.org/), React 采用 ReactDOMServer 调用 renderToString() 方法。
- gatsbyjs:服务端 React 渲染框架(参考查看: https://www.gatsbyjs.org/)。
- nuxt.js:服务器端渲染 Vue 组件框架(参考查看:https://nuxtjs.org/), Vue 采用 vue-server-renderer 调用 renderToString() 方法。
协作方式:
- 后端专注于业务功能实现和 API 接口封装。
- 前端负责实现页面前端交互,根据后端 API 接口拼装前端模板,页面渲染,以及服务器维护。
选型建议:
- 前端要处理 Node server 的机器环境、代码部署、日志、容灾、监控等以往后端人员需要具备运维知识,前端人员的综合能力要求会比以往要高。
- 前端项目开发周期变长了,需要事先和产品、运营沟通排期问题。
# PWA 技术方案和实现思路
Progressive Web App,简称 PWA,PWA 应用是使用特定技术和标准模式来开发的 Web 应用,这将同时赋予它们 Web 应用和原生应用的特性。
技术优势:
- 用户可以用手机屏幕启动应用,即使在离线状态或者弱网下,通过事先缓存的资源,也可正常加载运行当前应用,可以完全消除对网络的依赖,从而给用户非常可靠的体验。
- 因为预先缓存了资源,部分资源无须经过网络,即秒开页面。
- 和移动设备上的原生应用一样,具有沉浸式的用户体验。
- 可以给用户发送离线推送消息。
技术实现:
- 全站改造成 HTTPS,没有 HTTPS 就没有 Service Worker。
- 应用 Service Worker 技术提升性能,离线提供静态资源文件,提升首屏用户体验。
- 使用 App Manifest。
- 最后可以考虑离线消息推送等功能。
浏览器兼容性:
- ServiceWorkerGlobalScope API:88%
- Web App Manifest 83%
# 页面加载策略优化
- 懒加载
- 预加载
- 预渲染
- 按需加载
下面具体展开讲讲。
# 懒加载
懒加载也叫延迟加载,指的是长网页中延迟加载特定元素(可以是图片,也可以是 JS/CSS 文件,当然也可以是 JavaScript 的特定函数和方法,以下简称“懒加载元素”)。
好处:可以减少当前屏无效资源的加载。
技术实现举例:把页面上“懒加载元素”src 属性设置为空字符,把真实的 src 属性写在 data-lazy 属性中,当页面滚动的时候监听 scroll 事件,如果“懒加载元素”在可视区域内,就把图片的 src 属性或者文件 URL 路径设置成 data-lazy 属性值。
# 预加载
可以使用预加载让浏览器来预先加载某些资源(比如图片、JS/CSS/模板),而这些资源是在将来才会被使用到的。简单来说,就是将所需资源提前加载到浏览器本地,这样后面在需要使用的时候就可以直接从浏览器缓存中取了,而不用再重新开始加载。
使用场景:如果你希望这个资源能尽快显示给用户,就可以使用预加载。
好处:减少用户后续加载资源等待的时间。
技术实现举例:
- HTML 标签:
<img src="https://xxx.jpg" style="display: none" />
2、使用 Image 对象:
const image = new Image();
image.src = 'https://xxx.jpg';
3、使用 preload、prefetch 和 preconnect:
<link rel=“preload” href=“src/style.css” as=“style”>
<link rel="prefetch" href="scr/image.png" />
<link rel="dns-prefetch" href="https://my.com" />
<link rel="preconnect" href="https://my.com" crossorigin />
# 预渲染
有一种预加载组件的方式就是提前渲染它。在页面中渲染组件,但是并不在页面中展示。也就是渲染完成后,先隐藏起来,用的时候再展示。
实现举例:
<link rel="prerender" href="https://my.com" />
# 按需加载
- 常规按需加载(如 JS 原生、jQuery)
- 不同 App 按需加载(如 JS-SDK 脚本文件)
- 不同设备按需加载(如 PC 端和 HTML5 端样式文件)
- 不同分辨率按需加载(CSS Media Query)
React 异步加载举例:
const componentA = (location, callback) => {
require.ensure(
[],
(require) => {
callback(null, require('modules/componentA'));
},
'componentA'
);
};
const componentB = (location, callback) => {
require.ensure(
[],
(require) => {
callback(null, require('modules/componentB'));
},
'componentB'
);
};
<Router history={history}>
<Route path="/" component={App}>
<Route path="componentA" getComponent={componentA}></Route>
<Route path="componentB" getComponent={componentB}></Route>
</Route>
</Router>;
Vue 异步加载举例:
import Vue from 'vue';
import App from './App.vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter);
const componentA = resolve => require(['src/a.vue' ], resolve);
const componentB = resolve => require(['src/b.vue' ], resolve);
const router = new VueRouter({
routes: [{path:"a”,name:"/a”,component:componentA},
{path:"b”,name:"/b”,component:componentB}]
})
new Vue({
el: '#app',
router: router,
render: h => h(App)
})
# 接口服务调用优化
1、接口合并:一个页面的众多业务接口和依赖的第三方接口,合并为一个部署在集群的接口统一调用,以减少页面接口请求数。
2、接口上 CDN:主要基于接口性能考虑,我们可以把不需要实时更新的接口同步至 CDN,等此接口内容变更之后自动同步至 CDN 集群上。如果一定时间内未请求到数据,会用源站接口再次请求。
3、接口域名上 CDN:增强可用性、稳定性。
4、接口降级:核心接口进行降级用基础接口进行业务实现,比如千人千面的推荐接口,在大促时间点可以直接运营编辑的数据。另外如果接口无访问,建议使用兜底数据。
5、接口监控:监控接口成功率,不只是常说的 TP99,也包括弱网、超时、网络异常、网络切换等一段情况的监控情况。排查出来问题后,需要联合后端、运维、网络岗位人员一并解决。
# 接口缓存策略优化
1、Ajax/fetch 缓存:前端请求时候带上 cache,依赖浏览器本身缓存机制。
2、本地缓存:异步接口数据优先使用本地 localStorage 中的缓存数据。
3、多次请求:接口数据本地无 localStorage 缓存数据,重新再次发出 ajax 请求。