优化了一丢丢性能。
支持 srcList
上文提到过一点:图片加载失败,加载备选图片或展示error
占位符。
展示error
占位符我们可以通过error
状态去控制,但是加载备选图片的功能还没有完成。
主要思路如下:
-
将入参
src
改为srcList
,值为图片url
或图片(含备选图片)的url
数组; -
从第一张开始加载,若失败则加载第二张,直到某一张成功或全部失败,流程结束。类似于 tapable[4] 的
AsyncSeriesBailHook
。
对入参进行处理:
const removeBlankArrayElements = (a: string[]) => a.filter((x) => x);
const stringToArray = (x: string | string[]) => (Array.isArray(x) ? x : [x]);
function useImage({ srcList }: { srcList: string | string[] }): {
src: string | undefined,
loading: boolean,
error: any,
} {
// 获取url数组
const sourceList = removeBlankArrayElements(stringToArray(srcList));
// 获取用于缓存的键名
const sourceKey = sourceList.join(“”);
}
接下来就是重要的加载流程啦,定义promiseFind
方法,用于完成以上加载图片的逻辑。
/**
* 注意 此处将imgPromise作为参数传入,而没有直接使用imgPromise
* 主要是为了扩展性
* 后面会将imgPromise方法作为一个参数由使用者传入,使得使用者加载图片的操作空间更大
* 当然若使用者不传该参数,就是用默认的imgPromise方法
*/
function promiseFind(
sourceList: string[],
imgPromise: (src: string) => Promise
): Promise {
let done = false;
// 重新使用Promise包一层
return new Promise((resolve, reject) => {
const queueNext = (src: string) => {
return imgPromise(src).then(() => {
done = true;
// 加载成功 resolve
resolve(src);
});
};
const firstPromise = queueNext(sourceList.shift() || “”);
// 生成一条promise链[队列],每一个promise都跟着catch方法处理当前promise的失败
// 从而继续下一个promise的处理
sourceList
.reduce((p, src) => {
// 如果加载失败 继续加载
return p.catch(() => {
if (!done) return queueNext(src);
return;
});
}, firstPromise)
// 全都挂了 reject
.catch(reject);
});
}
再来改动useImage
。
const cache: {
- [key: s