128 lines
3.1 KiB
JavaScript
128 lines
3.1 KiB
JavaScript
// utils/preload.js
|
||
export class ImagePreloader {
|
||
constructor() {
|
||
this.cache = new Map();
|
||
}
|
||
|
||
/**
|
||
* 预加载单张图片
|
||
* @param {string} src - 图片地址
|
||
* @returns {Promise<boolean>}
|
||
*/
|
||
async preload(src) {
|
||
if (!src) return false;
|
||
|
||
// 检查缓存
|
||
if (this.cache.has(src)) {
|
||
return true;
|
||
}
|
||
|
||
// data URL 直接返回
|
||
if (src.startsWith('data:')) {
|
||
this.cache.set(src, true);
|
||
return true;
|
||
}
|
||
|
||
try {
|
||
// 本地图片和网络图片都需要真正加载
|
||
if (src.startsWith('/')) {
|
||
// 对于本地图片,使用Image对象加载
|
||
await new Promise((resolve, reject) => {
|
||
const img = new Image();
|
||
img.onload = () => resolve();
|
||
img.onerror = reject;
|
||
img.src = src;
|
||
});
|
||
this.cache.set(src, true);
|
||
console.log('本地图片预加载成功:', src);
|
||
return true;
|
||
} else {
|
||
// 对于网络图片,使用uni.getImageInfo
|
||
await uni.getImageInfo({ src });
|
||
this.cache.set(src, true);
|
||
console.log('网络图片预加载成功:', src);
|
||
return true;
|
||
}
|
||
} catch (error) {
|
||
console.warn('图片预加载失败:', src, error);
|
||
this.cache.set(src, false);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 批量预加载图片
|
||
* @param {string[]} srcList - 图片地址数组
|
||
* @param {number} concurrency - 并发数
|
||
* @returns {Promise<Array<{src: string, success: boolean}>>}
|
||
*/
|
||
async preloadAll(srcList, concurrency = 3) {
|
||
const results = [];
|
||
const queue = [...srcList];
|
||
|
||
// 执行并发下载
|
||
const workers = [];
|
||
for (let i = 0; i < concurrency; i++) {
|
||
workers.push(this.worker(queue, results));
|
||
}
|
||
|
||
await Promise.all(workers);
|
||
return results;
|
||
}
|
||
|
||
async worker(queue, results) {
|
||
while (queue.length > 0) {
|
||
const src = queue.shift();
|
||
if (src) {
|
||
const success = await this.preload(src);
|
||
results.push({ src, success });
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 清理缓存
|
||
*/
|
||
clearCache() {
|
||
this.cache.clear();
|
||
}
|
||
|
||
/**
|
||
* 预加载图片并设置到 img 标签
|
||
* @param {string} src - 图片地址
|
||
* @param {number} timeout - 超时时间
|
||
* @returns {Promise<string>} 返回图片临时路径
|
||
*/
|
||
async preloadToTemp(src, timeout = 10000) {
|
||
if (src.startsWith('/') || src.startsWith('data:')) {
|
||
return src;
|
||
}
|
||
|
||
return new Promise((resolve, reject) => {
|
||
const timer = setTimeout(() => {
|
||
reject(new Error('图片下载超时'));
|
||
}, timeout);
|
||
|
||
uni.downloadFile({
|
||
url: src,
|
||
success: (res) => {
|
||
clearTimeout(timer);
|
||
if (res.statusCode === 200) {
|
||
const tempPath = res.tempFilePath;
|
||
this.cache.set(src, tempPath);
|
||
resolve(tempPath);
|
||
} else {
|
||
reject(new Error(`下载失败: ${res.statusCode}`));
|
||
}
|
||
},
|
||
fail: (error) => {
|
||
clearTimeout(timer);
|
||
reject(error);
|
||
}
|
||
});
|
||
});
|
||
}
|
||
}
|
||
|
||
// 创建单例
|
||
export default new ImagePreloader(); |