Revert "x-img: simplify logic of cache"

This reverts commit d86e9406d3.
pull/460/head
Varun Patil 2023-02-26 15:08:02 -08:00
parent 881bab10df
commit f06c6fdcbf
1 changed files with 55 additions and 15 deletions

View File

@ -6,7 +6,7 @@
import { defineComponent } from "vue"; import { defineComponent } from "vue";
import { fetchImage } from "./XImgCache"; import { fetchImage } from "./XImgCache";
const BLOB_CACHE: { [src: string]: string } = {}; const BLOB_CACHE: { [src: string]: [number, string] } = {};
const BLANK_IMG = const BLANK_IMG =
"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"; "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
@ -26,11 +26,13 @@ export default defineComponent({
data: () => { data: () => {
return { return {
dataSrc: BLANK_IMG, dataSrc: BLANK_IMG,
isDestroyed: false,
}; };
}, },
watch: { watch: {
src() { src(newSrc, oldSrc) {
this.cleanup(oldSrc);
this.loadImage(); this.loadImage();
}, },
}, },
@ -39,9 +41,15 @@ export default defineComponent({
this.loadImage(); this.loadImage();
}, },
beforeDestroy() {
this.cleanup(this.src);
this.isDestroyed = true;
},
methods: { methods: {
async loadImage() { async loadImage() {
if (!this.src) return; if (!this.src) return;
this.isDestroyed = false;
// Just set src if not http // Just set src if not http
if (this.src.startsWith("data:") || this.src.startsWith("blob:")) { if (this.src.startsWith("data:") || this.src.startsWith("blob:")) {
@ -51,20 +59,35 @@ export default defineComponent({
// Fetch image with axios // Fetch image with axios
try { try {
const src = this.src; // Use BLOB from cache assuming it exists
if (BLOB_CACHE[src]) { const usedCache = (src: string) => {
this.dataSrc = BLOB_CACHE[src]; if (BLOB_CACHE[src]) {
return; this.dataSrc = BLOB_CACHE[src][1];
} BLOB_CACHE[src][0]++;
return true;
}
return false;
};
const newBlob = await fetchImage(src); // Check if the blob cache exists
if (this.src === src) { if (!usedCache(this.src)) {
const blobUrl = URL.createObjectURL(newBlob); const src = this.src;
BLOB_CACHE[src] = this.dataSrc = blobUrl; const newBlob = URL.createObjectURL(await fetchImage(src));
setTimeout(() => { if (this.src !== src || this.isDestroyed) {
if (BLOB_CACHE[src] === blobUrl) delete BLOB_CACHE[src]; URL.revokeObjectURL(newBlob); // the src has changed, abort
URL.revokeObjectURL(blobUrl); return;
}, 60 * 1000); }
// Check if the blob cache exists now
// In this case, someone else already created the blob
// Free up the current blob and use the existing one instead
if (usedCache(src)) {
URL.revokeObjectURL(newBlob);
} else {
// Create new blob cache entry
this.dataSrc = newBlob;
BLOB_CACHE[src] = [1, this.dataSrc];
}
} }
} catch (error) { } catch (error) {
this.dataSrc = BLANK_IMG; this.dataSrc = BLANK_IMG;
@ -76,6 +99,23 @@ export default defineComponent({
if (this.dataSrc === BLANK_IMG) return; if (this.dataSrc === BLANK_IMG) return;
this.$emit("load", this.dataSrc); this.$emit("load", this.dataSrc);
}, },
async cleanup(src: string) {
if (!src) return;
// Wait for 1s before collecting garbage
await new Promise((r) => setTimeout(r, 1000));
// Clean up blob cache
const cache = BLOB_CACHE[src];
if (!cache) return;
// Remove blob from cache
if (--cache[0] <= 0) {
URL.revokeObjectURL(cache[1]);
delete BLOB_CACHE[src];
}
},
}, },
}); });
</script> </script>