perf: Use cache for all remote resources

This commit is contained in:
Peng-YM
2022-07-11 20:46:16 +08:00
parent 51e3593ac2
commit 5698208a47
10 changed files with 482 additions and 39 deletions

View File

@@ -1,12 +1,14 @@
import { HTTP } from '@/vendor/open-api';
import { hex_md5 } from '@/vendor/md5';
import resourceCache from '@/utils/resource-cache';
const cache = new Map();
const tasks = new Map();
export default async function download(url, ua) {
ua = ua || 'Quantumult%20X/1.0.29 (iPhone14,5; iOS 15.4.1)';
const id = ua + url;
if (cache.has(id)) {
return cache.get(id);
const id = hex_md5(ua + url);
if (tasks.has(id)) {
return tasks.get(id);
}
const http = HTTP({
@@ -16,18 +18,27 @@ export default async function download(url, ua) {
});
const result = new Promise((resolve, reject) => {
http.get(url)
.then((resp) => {
const body = resp.body;
if (body.replace(/\s/g, '').length === 0)
reject(new Error('订阅内容为空!'));
else resolve(body);
})
.catch(() => {
reject(new Error(`无法下载 URL${url}`));
});
// try to find in app cache
const cached = resourceCache.get(id);
if (cached) {
resolve(cached);
} else {
http.get(url)
.then((resp) => {
const body = resp.body;
if (body.replace(/\s/g, '').length === 0)
reject(new Error('远程资源内容为空!'));
else {
resourceCache.set(id, body);
resolve(body);
}
})
.catch(() => {
reject(new Error(`无法下载 URL${url}`));
});
}
});
cache.set(id, result);
tasks.set(id, result);
return result;
}

View File

@@ -0,0 +1,47 @@
import $ from '@/core/app';
import { CACHE_EXPIRATION_TIME_MS, RESOURCE_CACHE_KEY } from '@/constants';
class ResourceCache {
constructor(expires) {
this.expires = expires;
if (!$.read(RESOURCE_CACHE_KEY)) {
$.write('{}', RESOURCE_CACHE_KEY);
}
this.resourceCache = JSON.parse($.read(RESOURCE_CACHE_KEY));
this._cleanup();
}
_cleanup() {
// clear obsolete cached resource
let clear = false;
Object.entries(this.resourceCache).forEach((entry) => {
const [id, updated] = entry;
if (new Date().getTime() - updated > this.expires) {
$.delete(`#${id}`);
delete this.resourceCache[id];
clear = true;
}
});
if (clear) this._persist();
}
_persist() {
$.write(JSON.stringify(this.resourceCache), RESOURCE_CACHE_KEY);
}
get(id) {
const updated = this.resourceCache[id];
if (updated && new Date().getTime() - updated <= this.expires) {
return $.read(`#${id}`);
}
return null;
}
set(id, value) {
this.resourceCache[id] = new Date().getTime();
this._persist();
$.write(value, `#${id}`);
}
}
export default new ResourceCache(CACHE_EXPIRATION_TIME_MS);