cancel image downloading when unmounting

This commit is contained in:
Eric 2024-07-01 17:00:43 +10:00
parent c7a8a83e43
commit 5a5dd68af6
No known key found for this signature in database
2 changed files with 36 additions and 10 deletions

View File

@ -1,5 +1,5 @@
<script setup> <script setup>
import { inject, ref, onMounted, computed, watch } from 'vue' import { inject, ref, onMounted, computed, watch, onUnmounted } from 'vue'
import SpinnerLoading from '@/components/SpinnerLoading.vue' import SpinnerLoading from '@/components/SpinnerLoading.vue'
const codexApi = inject('codexApi') const codexApi = inject('codexApi')
@ -26,33 +26,56 @@ const props = defineProps({
// The value must match one of these strings // The value must match one of these strings
return ['pending', 'approved', 'banned'].includes(value) return ['pending', 'approved', 'banned'].includes(value)
} }
},
timeout: {
type: Number,
default() {
return 5000
}
} }
}) })
const hidden = computed(() => props.cid === undefined) const hidden = computed(() => props.cid === undefined)
const blurred = computed(() => ['pending', 'banned'].includes(props.moderated)) const blurred = computed(() => ['pending', 'banned'].includes(props.moderated))
const controller = new AbortController();
async function fetchImage(cid) { async function fetchImage(cid) {
if (hidden.value) { if (hidden.value) {
return return
} }
loading.value = true loading.value = true
const timeoutSignal = AbortSignal.timeout(props.timeout);
try { try {
let res = await codexApi.downloadLocal(cid) let response
if (res.status === 404 && !props.localOnly) { let options = {
res = await codexApi.download(cid) // This will abort the fetch when either signal is aborted
signal: AbortSignal.any([controller.signal, timeoutSignal]),
} }
if (!res.ok) { if (props.localOnly) {
throw new Error(`${res.status} ${res.statusText}`) response = await codexApi.downloadLocal(cid, options)
} else {
response = await codexApi.download(cid, options)
}
if (!response.ok) {
throw new Error(`${response.status} ${response.statusText}`)
} }
try { try {
const blob = await res.blob() const blob = await response.blob()
imgSrc.value = URL.createObjectURL(blob) imgSrc.value = URL.createObjectURL(blob)
} catch (e) { } catch (e) {
error.value = `not an image (error: ${e.message})` error.value = `not an image (error: ${e.message})`
} }
} catch (e) { } catch (e) {
error.value = `failed to download cid data: ${e.message}` if (e.name === "AbortError") {
console.log(`image fetch aborted for cid ${props.cid}`)
} else if (e.name === "TimeoutError") {
// Notify the user of timeout
console.error(`image fetch for cid ${props.cid} timed out after ${props.timeout}ms`)
} else {
error.value = `failed to download cid data: ${e.message}`
}
} finally { } finally {
loading.value = false loading.value = false
} }
@ -60,6 +83,9 @@ async function fetchImage(cid) {
watch(() => props.cid, fetchImage, {immediate: true}) watch(() => props.cid, fetchImage, {immediate: true})
onUnmounted(() => {
controller.abort() // abort image fetch
})
</script> </script>
<template> <template>

View File

@ -2,8 +2,8 @@ export default {
install: (app, { codexRestUrl, myAddress }) => { install: (app, { codexRestUrl, myAddress }) => {
const codexApi = { const codexApi = {
info: () => fetch(`${codexRestUrl}/debug/info`), info: () => fetch(`${codexRestUrl}/debug/info`),
download: (cid) => fetch(`${codexRestUrl}/data/${cid}/network`), download: (cid, options) => fetch(`${codexRestUrl}/data/${cid}/network`, options),
downloadLocal: (cid) => fetch(`${codexRestUrl}/data/${cid}`), downloadLocal: (cid, options) => fetch(`${codexRestUrl}/data/${cid}`, options),
spr: () => fetch(`${codexRestUrl}/spr`) spr: () => fetch(`${codexRestUrl}/spr`)
} }