Web/14-前端性能优化/04-静态资源优化.md
2021-07-29 11:08:52 +08:00

602 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: 04-静态资源优化
publish: true
---
<ArticleTopAd></ArticleTopAd>
## 图片格式和应用场景
### JPEG 格式
JPEGJoint Photographic Experts Group是一种针对彩色照片而广泛使用的有损压缩图形格式属于位图。
常用文件扩展名为`.jpg`,也有 `.jpeg`和`.jpe`。JPEG 在互联网上常被应用于存储和传输照片。
- 适合:颜色丰富的照片、彩色图大焦点图、通栏 banner 图;结构不规则的图形。
- 不适合:线条图形和文字、图标图形,因为它的压缩算法不太这些类型的图形;并且不支持透明度。
### PNG 格式
PNGPortable Network Graphics是一种无损压缩的位图图形格式支持索引、灰度、RGB 三种颜色方案以及 Alpha 通道等特性。
PNG 最初是作为替代 GIF 来设计的,能够显示 256 色,文件比 JPEG 或者 GIF 大,但是 PNG 非常好的保留了图像质量。支持 Alpha 通道的半透明和透明特性。最高支持 24 位彩色图像PNG-24和 8 位灰度图像PNG-8
- 适合:纯色、**透明**、线条绘图,图标;边缘清晰、有大块相同颜色区域;需要带**半透明**的图片。
- 适合:由于是无损存储,所以不太适合体积太大的彩色图像
比如说,如果你需要带透明背景的图片,此时就可以用 png 格式的图。
### GIF 格式
GIFGraphics Interchange Format是一种位图图形格式以 8 位色(即 256 种颜色)重现真彩色的图像,采用 LZW 压缩算法进行编码。
支持 256 色仅支持完全透明和完全不透明如果需要带动画效果的图片GIF 是比较通用的选择。
- 适合:动画,图标。
- 不适合:每个像素只有 8 比特,不适合存储彩色图片。
### Webp 格式
Webp 是一种现代图像格式,可为图像提供无损压缩和有损压缩,这使得它非常灵活。由 Google 在购买 On2 Technologies 后发展出来,以 BSD 授权条款发布。
Webp的优秀算法能同时保证图像质量和较小体积可以插入多帧实现动画效果可以设置透明度采用 8 位压缩算法。
无损的 Webp 比 PNG 小 26%,有损的 Webp 比 JPEG 小 25-34比 GIF 有更好的动画。
- 适合:适用于图形和半透明图像。
### 总结
- banner图、大图可以用 jpg、webp格式。
- 图标、带透明背景的图,可以用 png 格式。
- 带动画效果的图,可以用 gif 格式。
## 图片优化的常见方法
### 1、用工具压缩图片
**压缩 PNG 图片**
- 工具:[node-pngquant-native](https://www.npmjs.com/package/node-pngquant-native)
- 介绍跨平台、压缩比特别高压缩png24非常好。
安装方法:
```
npm install node-pngquant-native
```
**压缩 JPEG 图片**
- 工具:[jpegtran](https://www.npmjs.com/package/jpegtran)
- 官网:<https://www.npmjs.com/package/jpegtran>
- 介绍跨平台但压缩的比率只有80-90%。
安装方法:
```bash
npm install g jpegtran
```
使用方法:
```bash
jpegtran -copy none -optimize -outfile output_file.jpg input_file.jpg
```
**压缩 GIF 图**
- 工具Gifsicle
- 官网(含安装方法):<https://www.lcdf.org/gifsicle/>
- 介绍Gifsicle 通过改变每帧比例,减小 gif文件大小同时可以使用透明来达到更小的文件大小是目前公认的最好的解决方案。
使用方法:
```bash
# 压缩命令。注意这里是将压缩级别设置为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
```css
@media screen and (max-width:640px) {
my_image{
width:640px;
}
}
```
**方法3**img标签的 `srcset` 属性。这个是 H5的新特性。
代码举例:
```html
<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** 的图片加载方式。也就是说,在大图没有完全加载出来的情况下,先这张图对应的的低质量图片进行占位。
LQIPLow Quality Image Placeholders低质量图像占位符。这种技术背后的想法是在网络环境较差的情况下你可以尽快向用户展示完全可用的网页为他们提供更好的体验。即使在更好的网络连接上这仍然为用户提供了更快的可用页面并且改善了体验。
- 安装 LQIP 工具:`npm install lqip`
- GitHub源码https://github.com/zouhir/lqip-loader
代码举例:(将目标图片转换为 LQIP 形式的图)
```js
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** 的图片加载方式。
SQIPSVG Quality Image Placeholders SVG 格式的图像占位符。
- 安装 SQIP 工具:`npm install sqip`
- GitHub 源码:<https://github.com/axe312ger/sqip>
代码举例:(将目标图片转换为 SQIP 形式的图)
```js
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 链接上增加不同特殊参数,服务器自动化生成。通过这些参数,可以设置图片的不同格式、大小、质量。
**常见处理方式**
- 图片裁剪:按长边、短边、填充、拉伸等缩放。
- 图片格式转换:支持 JPGGIFPNGWebP 等,支持不同的图片压缩率。
- 图片处理:添加图片水印、高斯模糊、重心处理、裁剪边框等。
- 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 节点数。
- 减少无语义代码(比如: <div class=“clear”></div> 消除浮动其实可以用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可以在正确的时间进行渲染setTimeoutcallback和setIntervalcallback无法保证 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 压缩工具:
- html-minifierhttps://www.npmjs.com/package/html-minifier
CSS 压缩工具:
- clean-csshttps://www.npmjs.com/package/clean-css
JavaScript 压缩工具:
- uglify-jshttps://www.npmjs.com/package/uglify-js
- 使用方法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 方式优化