31 lines
1.0 KiB
TypeScript
31 lines
1.0 KiB
TypeScript
import { apiRaw } from "../api/client";
|
|
|
|
const MAX = 600;
|
|
const cache = new Map<string, Promise<string>>(); // 插入序 ≈ LRU(命中时重插)
|
|
|
|
// 带鉴权取图 → objectURL。后端 Bearer-only,<img>/<iframe> 直挂 /api 必 401,
|
|
// 故图片一律走此通道;URL 含内容 hash 不可变,会话内可安全长驻缓存。
|
|
export async function fetchObjectUrl(url: string, signal?: AbortSignal): Promise<string> {
|
|
const hit = cache.get(url);
|
|
if (hit) {
|
|
cache.delete(url);
|
|
cache.set(url, hit);
|
|
return hit;
|
|
}
|
|
const p = (async () => {
|
|
const res = await apiRaw(url, { signal });
|
|
return URL.createObjectURL(await res.blob());
|
|
})();
|
|
p.catch(() => cache.delete(url)); // 失败出缓存,下次调用重试
|
|
cache.set(url, p);
|
|
while (cache.size > MAX) {
|
|
const oldest = cache.keys().next().value as string;
|
|
cache.delete(oldest); // 不 revoke:可能仍被在屏 <img> 引用;≤600 条会话内 blob 可接受
|
|
}
|
|
return p;
|
|
}
|
|
|
|
export function __resetImageCache(): void {
|
|
cache.clear();
|
|
}
|