前端的性能优化,图片优化是必不可少的重要环节,大部分网站页面的构成都少不了图片的渲染。尤其在电商类项目,往往存在大量的图片,如 banner 广告图,菜单导航图,商品列表图等。图片加载数量多以及图片体积过大往往会影响页面加载速度,造成不良的用户体验。
基于上述问题的主要问题是图片数量和图片体积,所以应该怎么提高图片加载速度,提升用户体验。其实图片优化有非常多且优秀的方案,都可以从中借鉴,最后我们对图片进行不同方向的整体优化。
使用合适的图片格式
目前广泛应用的 WEB 图片格式有 JPEG/JPG、PNG、GIF、WebP、Base64、SVG 等,这些格式都有各自的特点,以下大概简单总结如下:
使用合适的图片格式通常可以带来更小的图片字节大小,通过合理压缩率,可以减少图片大小,且不影响图片质量。
降低网络传输
小程序使用
腾讯云图片服务器
,提供很多图片处理功能,比如
图片缩放、图片降质,格式转换,图片裁剪、图片圆角
等功能。这些功能可以通过在图片
URL
中添加规定参数就能实现,图片服务器会根据参数设置提前将图片处理完成并保存到
CDN
服务器,这样大大的减少图片传输大小。
目前后台接口下发返回的图片 URL 都是未设置图片参数预处理,比如一张
800x800
尺寸高清的商品图,体积大概
300k
左右,这样就很容易导致图片加载和渲染慢、用户流量消耗大,严重影响了用户体验。所以我们结合腾讯云的图片处理功能,网络图片加载前,先检测是否是腾讯云域名的图片
URL
,如果
域名
匹配,对图片
URL
进行预处理,预处理包括
添加缩放参数
,
添加降质参数
,
添加WebP参数
的方式减少图片网络传输大小
我们先看一张通过图片服务器是腾讯云图片处理能力,通过设置图片缩放/降质/WebP,一张尺寸
800x800
,体积
246KB
图片,最后输出生成
25.6KB
,图片体积足足减少了
80%
,效果显著。
目前业务后台都是原图上传,原始图尺寸可能比客户端实际显示的尺寸要大,一方面导致图片加载慢,另一方面导致用户流量的浪费,其中如果是一张很大尺寸图片加载也会影响渲染性能,会让用户感觉卡顿,影响用户体验。通过添加缩放参数的方式,指定图片服务器下发更小和更匹配实际显示
size
的图片尺寸。
图片服务器支持图片质量,取值范围
0-100
,默认值为原图质量,通过降低图片质量可以减少图片大小,但是质量降低太多也会影响图片的显示效果,网络默认降图片质量参数设置为
85
,同时通过小程序提供的:
wx.getNetworkType
、
wx.onNetworkStatusChange
、
offNetworkStatusChange
的接口监听网络状态变化来获取当前用户的网络类型
networkType
,比如用户当前使用的
4G
网络,则图片质量会动态设置为
80
,对于大部分业务情况,一方面可以大幅减少图片下载大小和保证用户使用体验,另一方面节省用户浏览 ,目前添加图片降质参数至少可以减少
30-40%
的图片大小。
* 设置网络情况
const
setNetwork
= (
res: Record<
string
,
any
>
) => {
const
{ isConnected =
true
, networkType =
'wifi'
} = res;
this
.
globalData
.
isConnected
= isConnected;
this
.
globalData
.
networkType
= networkType.
toLowerCase
();
this
.
events
.
emit
(
EventsEnum
.
UPDATE_NETWORK
, networkType);
wx.
getNetworkType
({
success
:
(
res
) =>
setNetwork
(res) });
wx.
offNetworkStatusChange
(
(
res
) =>
setNetwork
(res));
wx.
onNetworkStatusChange
(
(
res
) =>
setNetwork
(res));
* 根据网络环境设置不同质量图片
const
ImageQuality
:
Record
<
string
,
number
> = {
wifi
:
85
,
'5g'
:
85
,
'4g'
:
80
,
'3g'
:
60
,
'2g'
:
60
,
* 获取图片质量
export
const
getImageQuality
= (
) =>
ImageQuality
[
getApp
().
globalData
.
networkType
??
'wifi'
];
使用 WebP
前面简单介绍不同的图片格式都有各自的优缺点和使用场景,其中
WebP
图片格式提供有损压缩与无损压缩的图片格式。按照
Google
官方的数据,与
PNG
相比,
WebP
无损图像的字节数要少
26%
,
WebP
有损图像比同类
JPG
图像字节数少
25-34%
。现如今各大互联网公司的产品都已经使用了,如淘宝、京东和美团等。
这里放一个
WebP 示例链接(GIF、PNG、JPG 转 Webp)
,直观感受
WebP
在图片大小上的优势。
在移动端中
WebP
的兼容性,大部分数用户都已经支持了
Can I use... Support tables for HTML5, CSS3, etc
,
针对
png
/
jpg
图片格式,自动添加
WebP
参数,转成
WebP
图片格式。虽然
WebP
相比
png
/
jpg
图片解码可能需要更长时间,但相对网络传输速度提升还是很大。目前
ios 13
系统版本有不少用户量的占比,小程序端获取当前系统版本,降级处理不添加
WebP
参数。
const checkSupportWebp = () => {
const { system } = wx.getSystemInfoSync();
const [platform, version] = system.split(' ');
if (platform.toLocaleUpperCase() === PlatformEnum.IOS) {
return Number(version.split('.')[0]) > IOS_VERSION_13;
return true;
提示:由于目前图片服务器并不支持、SVG、GIF
转WebP
,并没有做处理
测试我们小程序首页列表接口加载图片,来对比优化前后的效果
优化前 | 图片数 | 不支持 WebP | 支持 WebP |
---|
2300K | 10 | 523K (降低 77%+) | 315K (降低 86%+) |
248M | 100 | 69M (降低 72%+) | 38M (降低 84%+) |
经过我们通过使用腾讯云图片服务器的图片处理功能,以及动态处理图片格式的方式,减少图片体积,提高图片加载速度,带来的收益比非常可观的
图片懒加载
懒加载是一种性能优化的方式,将页面内未出现在可视区域内的图片先不做加载, 等到滚动到可视区域后再去加载,对于页面加载性能上会有很大的提升,也提高了用户体验。
使用小程序提供Intersection Observer API
,监听某些节点是否可以被用户看见、有多大比例可以被用户看见。这样我们就能判断图片元素是否在可是范围中,进行图片加载。
我们基于小程序的Intersection Observer API
,封装一个监听模块曝光 IntersectionObserver
函数工具,提供以下用法
import IntersectionObserver from 'utils/observer/observer';
const ob = new IntersectionObserver({
selector: '.goods-item',
observeAll: true,
context: this,
delay: 200,
onEach: ({ dataset }) => {
const { key } = dataset || {};
return key;
onFinal: (data) => {
if (!data) return;
console.log('module view data', data);
ob.connect();
ob.disconnect();
ob.reconnect();
然后在我们的FreeImage
图片组件,添加可视区域加载图片的功能,以下是部分代码
import IntersectionObserver from 'utils/observer';
Component({
properties: {
src: String,
* 是否开启可视区域加载图片
observer: {
type: Boolean,
value: false,
data: {
isObserver: false,
lifetimes: {
attached() {
if (this.data.observer) {
this.createObserver();
methods: {
* 监听图片是否进入可视区域
createObserver() {
const ob = new IntersectionObserver({
selector: '.free-image',
observeAll: true,
context: this,
onFinal: (data = []) => {
data.forEach((item: any) => {
this.setData({
isObserver: true,
ob.disconnect();
ob.connect();
<free-image observer src="{{ src }}" />
测试我们小程序首页列表,使用图片懒加载的效果
通过使用图片懒加载的功能,减少图片数量的加载,有效提高页面加载性能。在上述我们已经对图片体积进行优化过,所以在我们小程序中,只有在网络情况较差的情况下,才会自动开启图片懒加载功能。
优化请求数
我们项目中有很多本地图片资源,比如一些 icon 图标、标签类切图、背景图、图片按钮等。而小程序分包大小是有限制:整个小程序所有分包大小不超过 20M
,而单个分包/主包大小不能超过 2M
。所以为了减轻小程序体积,本地图片资源需要进行调整,比如图片压缩、上传到 CDN 服务器。这样能减少了小程序主包大小,而大部分图片都在腾讯云 CDN 服务器中,虽然可以加速资源的请求速度,当页面打开需要同时下载大量的图片的话,就会严重影响了用户的使用体验。
针对此问题,需要找到权衡点来实现来优化请求数,首先我们把图片资源进行分类,以及使用场景,最后确定我们方案如下:
较大体积的图片,选择上传到 CDN 服务器
单色图标使用 iconfont 字体图标,多彩图标则使用svg
格式
标签类的图片,则生成雪碧图之后上传到 CDN 服务器
图片体积小于10KB
,结合使用场景,则考虑base64
,比如一张图片体积为3KB
的背景图,由于小程序css background
不支持本地图片引入,可以使用 base64
方式实现
实现大图检测机制,及时发现图片不符合规范的问题,当发现图片尺寸太大,不符合商品图尺寸标准时会进行上报。在小程序开发版/体验版中,当我们设置开启Debug
模式,图片组件FreeImage
会自动检测到大图片时,显示当前图片尺寸、以及设置图片高亮/翻转
的方式提醒运营同学和设计同学进行处理
加载失败处理
使用腾讯云图片处理功能,URL
预处理转换后得新 URL,可能会存在少量图片不存在的异常场景导致加载失败
。遇到图片加载失败时,我们还是需要重新加载原始图片 URL, 之后会将错误图片 URL 上报到监控平台,方便之后调整 URL 预处理转换规则,同时也发现一部分错误的图片 URL 推动业务修改。
这是我们图片组件FreeImage
处理图片加载失败,以下是部分代码
onError(event: WechatMiniprogram.TouchEvent) {
const { src, useCosImage } = this.data;
this.setData({
loading: false,
error: true,
lazy: 'error',
if (useCosImage) {
wx.nextTick(() => {
this.setData({
formattedSrc: src,
app.aegis.report(AegisEnum.IMAGE_LOAD_FAIL, {
errMsg: event?.detail.errMsg,
this.triggerEvent('error', event.detail);
图片请求数检查
使用小程序开发者工具的体验评分功能,体验评分是一项给小程序的体验好坏打分的功能,它会在小程序运行过程中实时检查,分析出一些可能导致体验不好的地方,并且定位出哪里有问题,以及给出一些优化建议。
通过体验评分的结果,可以分析我们存在短时间内发起太多的图片请求,以及存在图片太大而有效显示区域较小。所以根据分析的结果,开发需要合理控制数量,可考虑使用雪碧图技术、拆分域名或在屏幕外的图片使用懒加载等。
图片在上传前在保持可接受的清晰度范围内同时减少文件大小,进行合理压缩。现如今有很多不错的图片压缩插件工具,就不在详情介绍了。
推荐一个比较优秀的图片压缩网站:TinyPNG使用智能有损压缩技术将您的 WebP, PNG and JPEG 图片的文件大小降低