1. 前言
随着小程序的发展,越来越多的小程序开始涉及到远程数据和图片资源的使用,在保证流畅体验的前提下,如何更好地对这些资源进行加载是非常关键的。本文将介绍一种小程序加载器的实现方式,主要是对远程图片资源进行按需预加载,提高了小程序的运行效率。
2. 加载器的设计思路
2.1 需求分析
前面提到了小程序很多时候需要远程数据和图片资源,若每次都请求获取这些资源,不仅效率低下,同时也会对用户体验造成一定的影响。所以我们需要做到按需预加载远程图片资源。
具体而言,我们可以在小程序初次加载的时候进行主体图片资源的预加载工作,在用户第一次访问到某个页面时再对该页面所需的图片资源进行加载,这样可以做到提前预留空间,避免了再次请求的卡顿和等待。
2.2 系统设计
基于上述需求,我们可以设计如下的图片预加载系统。首先,我们需要根据小程序的业务需求,从后端请求获取每个页面所需的图片资源和其他数据,并将它们暂时存储在本地。
其次,在小程序进入每个页面的时候,我们需要动态地加载每个页面所需的图片资源,这样可以在不浪费时间和数据的同时,保证用户能够流畅地访问每个页面。
最后,我们需要编写相关代码,将这个系统实现在小程序中。
3. 系统实现
3.1 数据请求处理
在小程序初次加载的时候,我们需要请求获取每个页面的资源。这个过程需要使用到小程序提供的wx.request()方法,在JS中使用Promise对象封装请求方法,方便后续的调用。
// Promise封装的请求方法
const fetch = (url) => {
return new Promise((resolve, reject) => {
wx.request({
url: url,
method: 'GET',
success: (res) => {
resolve(res);
},
fail: (err) => {
reject(err);
}
})
})
}
// 资源请求方法
const getResource = async (urlList) => {
let resList = [];
try {
// 并发请求走 Promise.all()
resList = await Promise.all(urlList.map(url => fetch(url)))
} catch (err) {
console.log(err);
}
return resList;
}
3.2 图片资源加载处理
接下来是图片资源的预加载工作。对于每个页面所需的图片资源,我们可以通过wx.getImageInfo()方法获取图片信息并进行缓存处理,避免了每次都重新请求获取图片信息。
为了实现图片的按需预加载,在进入每个页面的时候,我们需要动态地加载页面所需的图片资源,这个过程使用到了Promise对象的相关方法,下面是代码示例:
/**
* 动态预加载并缓存图片
* @param {string} src 图片资源地址
* @return {Promise} 返回一个Promise对象
*/
const loadImage = async (src) => {
return new Promise((resolve, reject) => {
wx.getImageInfo({
src: src,
success: (res) => {
// 缓存图片
tempImages.setCache(src, {
width: res.width,
height: res.height
})
resolve();
},
fail: (err) => {
reject(err);
}
})
})
}
/**
* 动态加载每个页面所需的图片资源
* @param {array} urlList 图片资源地址列表
*/
const loadEveryImage = async (urlList) => {
try {
let loads = urlList.map((url) => loadImage(url));
// 并发加载图片资源
await Promise.all(loads);
console.log('imgs load complete!');
} catch (err) {
console.error(err);
}
}
3.3 按需预加载图片资源
上述代码的前提是我们已经获取到需要加载的图片资源列表,接下来,我们需要对这个列表中的图片资源进行筛选,筛选出当前页面所需的资源,并将这些资源进行预加载,其余资源则存储到一个缓存队列中,以便后续的访问和使用。
下面是按需预加载图片资源的代码实现:
/**
* 对需要预加载的图片资源列表进行筛选
* @param {array} imgUrls 每个页面的图片资源列表
* @param {string} curPage 当前页面名称
* @return {array} 当前页面所需的图片资源和其余图片资源
*/
const filterImgUrls = (imgUrls, curPage) => {
let filterUrls = imgUrls.filter(item => {
let {page, url} = item;
return page === curPage;
})
let cacheUrls = imgUrls.filter(item => {
let {page} = item;
return page !== curPage;
})
return {
filterUrls,
cacheUrls,
}
}
/**
* 按需预加载图片资源
* @param {array} imgUrls 每个页面的图片资源列表
* @param {object} cache 缓存队列
* @param {string} curPage 当前页面名称
*/
const loadImgByPage = (imgUrls, cache, curPage) => {
// 筛选当前页面所需图片资源和缓存图片资源
let {filterUrls, cacheUrls} = filterImgUrls(imgUrls, curPage);
// 对当前页面所需的图片资源进行预加载
loadEveryImage(filterUrls.map(item => item.url)).then(() => {
// 将未加载的图片资源添加到缓存队列中
cache.addCacheItems(filterUrls.concat(cacheUrls));
});
}
3.4 图片资源的缓存处理
如果当前页面的图片资源全部加载完成,我们可以将剩余的图片资源存储到一个缓存队列中。当用户再次访问到该页面的时候,我们可以加载缓存队列中存储的资源,这样能够优化小程序的加载速度。
下面是图片资源的缓存处理代码实现:
/**
* 缓存队列
*/
class CacheList {
constructor () {
// 缓存队列最大长度
this.MAX_LENGTH = 100;
this.cache = [];
}
/**
* 添加缓存队列中的资源
* @param items
*/
addCacheItems (items) {
// 将当前页面所需的图片资源添加到数组末尾
this.cache.push(...items);
// 控制缓存队列长度,达到一定长度后就不存储新的资源
if (this.cache.length > this.MAX_LENGTH) {
this.cache.splice(0, this.cache.length - this.MAX_LENGTH);
}
}
/**
* 获取缓存队列中的资源
* @param page
*/
getCacheItems (page) {
let cache = this.cache;
let filterUrls = cache.filter(item => item.page === page)
let cacheUrls = cache.filter(item => item.page !== page);
this.cache = cacheUrls;
return filterUrls;
}
}
let tempImages = new CacheList();
3.5 实现代码集成
有了上述各个过程的代码实现,我们可以将它们总和集成起来,如下所示:
import { getResource } from 'resource.js'
/**
* 动态预加载并缓存图片
* @param {string} src 图片资源地址
* @return {Promise} 返回一个Promise对象
*/
const loadImage = async (src) => {
return new Promise((resolve, reject) => {
wx.getImageInfo({
src: src,
success: (res) => {
// 缓存图片
tempImages.setCache(src, {
width: res.width,
height: res.height
})
resolve();
},
fail: (err) => {
reject(err);
}
})
})
}
/**
* 动态加载每个页面所需的图片资源
* @param {array} urlList 图片资源地址列表
*/
const loadEveryImage = async (urlList) => {
try {
let loads = urlList.map((url) => loadImage(url));
// 并发加载图片资源
await Promise.all(loads);
console.log('imgs load complete!');
} catch (err) {
console.error(err);
}
}
/**
* 对需要预加载的图片资源列表进行筛选
* @param {array} imgUrls 每个页面的图片资源列表
* @param {string} curPage 当前页面名称
* @return {array} 当前页面所需的图片资源和其余图片资源
*/
const filterImgUrls = (imgUrls, curPage) => {
let filterUrls = imgUrls.filter(item => {
let {page, url} = item;
return page === curPage;
})
let cacheUrls = imgUrls.filter(item => {
let {page} = item;
return page !== curPage;
})
return {
filterUrls,
cacheUrls,
}
}
/**
* 按需预加载图片资源
* @param {array} imgUrls 每个页面的图片资源列表
* @param {object} cache 缓存队列
* @param {string} curPage 当前页面名称
*/
const loadImgByPage = (imgUrls, cache, curPage) => {
// 筛选当前页面所需图片资源和缓存图片资源
let {filterUrls, cacheUrls} = filterImgUrls(imgUrls, curPage);
// 对当前页面所需的图片资源进行预加载
loadEveryImage(filterUrls.map(item => item.url)).then(() => {
// 将未加载的图片资源添加到缓存队列中
cache.addCacheItems(filterUrls.concat(cacheUrls));
});
}
/**
* 缓存队列
*/
class CacheList {
constructor () {
// 缓存队列最大长度
this.MAX_LENGTH = 100;
this.cache = [];
}
/**
* 添加缓存队列中的资源
* @param items
*/
addCacheItems (items) {
// 将当前页面所需的图片资源添加到数组末尾
this.cache.push(...items);
// 控制缓存队列长度,达到一定长度后就不存储新的资源
if (this.cache.length > this.MAX_LENGTH) {
this.cache.splice(0, this.cache.length - this.MAX_LENGTH);
}
}
/**
* 获取缓存队列中的资源
* @param page
*/
getCacheItems (page) {
let cache = this.cache;
let filterUrls = cache.filter(item => item.page === page)
let cacheUrls = cache.filter(item => item.page !== page);
this.cache = cacheUrls;
return filterUrls;
}
}
let tempImages = new CacheList();
/**
* 对每个页面所需的资源进行统一加载
* @param pageName
*/
export const getNewPageRes = (pageName) => {
// 获取每个页面的图片资源地址列表等信息,并进行一些过滤处理
getResource(`res/${pageName}/res.json`).then(res => {
let {imgUrls} = res.data;
// 获取缓存队列中的图片资源
let cacheUrls = tempImages.getCacheItems(pageName);
// 添加缓存队列中的资源到当前页面所需资源列表中
imgUrls = imgUrls.concat(cacheUrls);
loadImgByPage(imgUrls, tempImages, pageName)
})
}
4. 总结
本文主要介绍了一种小程序加载器的实现方式,将远程图片资源按需预加载,能够提高小程序的运行效率,为用户带来更好的访问体验。同时,这种方案也可以被用于其他网络程序的实现中,具有一定的借鉴和参考意义。