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 { fetchImage } from "./XImgCache";
const BLOB_CACHE: { [src: string]: string } = {};
const BLOB_CACHE: { [src: string]: [number, string] } = {};
const BLANK_IMG =
"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
@ -26,11 +26,13 @@ export default defineComponent({
data: () => {
return {
dataSrc: BLANK_IMG,
isDestroyed: false,
};
},
watch: {
src() {
src(newSrc, oldSrc) {
this.cleanup(oldSrc);
this.loadImage();
},
},
@ -39,9 +41,15 @@ export default defineComponent({
this.loadImage();
},
beforeDestroy() {
this.cleanup(this.src);
this.isDestroyed = true;
},
methods: {
async loadImage() {
if (!this.src) return;
this.isDestroyed = false;
// Just set src if not http
if (this.src.startsWith("data:") || this.src.startsWith("blob:")) {
@ -51,20 +59,35 @@ export default defineComponent({
// Fetch image with axios
try {
const src = this.src;
// Use BLOB from cache assuming it exists
const usedCache = (src: string) => {
if (BLOB_CACHE[src]) {
this.dataSrc = BLOB_CACHE[src];
this.dataSrc = BLOB_CACHE[src][1];
BLOB_CACHE[src][0]++;
return true;
}
return false;
};
// Check if the blob cache exists
if (!usedCache(this.src)) {
const src = this.src;
const newBlob = URL.createObjectURL(await fetchImage(src));
if (this.src !== src || this.isDestroyed) {
URL.revokeObjectURL(newBlob); // the src has changed, abort
return;
}
const newBlob = await fetchImage(src);
if (this.src === src) {
const blobUrl = URL.createObjectURL(newBlob);
BLOB_CACHE[src] = this.dataSrc = blobUrl;
setTimeout(() => {
if (BLOB_CACHE[src] === blobUrl) delete BLOB_CACHE[src];
URL.revokeObjectURL(blobUrl);
}, 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) {
this.dataSrc = BLANK_IMG;
@ -76,6 +99,23 @@ export default defineComponent({
if (this.dataSrc === BLANK_IMG) return;
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>