mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-24 23:51:20 -08:00
refactor(core): CORE-19 type capture and preserve progress lifetimes
This commit is contained in:
1 parent
98a1800032
commit
ccf77c4ed2
49 files changed
+31570
-681
No files matched your search
@@ -0,0 +1,146 @@
|
||||
import ResourceScope from '../lifecycle/scope'
|
||||
|
||||
function requestImage(url: string, scale: number | undefined, owner: undefined): Promise<HTMLImageElement>
|
||||
function requestImage(url: string, scale: number | undefined, owner: ResourceScope): Promise<HTMLImageElement | undefined>
|
||||
function requestImage(url: string, scale: number | undefined, owner: ResourceScope | undefined): Promise<HTMLImageElement | undefined> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = owner ? owner.child() : new ResourceScope()
|
||||
let complete = false
|
||||
let releaseBlob = () => {}
|
||||
|
||||
function fail(error: unknown): void {
|
||||
if (complete)
|
||||
return
|
||||
complete = true
|
||||
try {
|
||||
request.dispose()
|
||||
}
|
||||
catch (cleanupError) {
|
||||
console.warn('Additional image cleanup failure:', cleanupError)
|
||||
}
|
||||
try {
|
||||
releaseBlob()
|
||||
}
|
||||
catch (cleanupError) {
|
||||
console.warn('Additional image cleanup failure:', cleanupError)
|
||||
}
|
||||
reject(error)
|
||||
}
|
||||
|
||||
function finish(image: HTMLImageElement): void {
|
||||
if (complete || request.closed)
|
||||
return
|
||||
complete = true
|
||||
try {
|
||||
request.dispose()
|
||||
resolve(image)
|
||||
}
|
||||
catch (error) {
|
||||
try {
|
||||
releaseBlob()
|
||||
}
|
||||
finally {
|
||||
reject(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
request.add(() => {
|
||||
if (!complete) {
|
||||
complete = true
|
||||
try {
|
||||
releaseBlob()
|
||||
}
|
||||
finally {
|
||||
resolve(undefined)
|
||||
}
|
||||
}
|
||||
})
|
||||
if (request.closed)
|
||||
return
|
||||
|
||||
function watch(image: HTMLImageElement, loaded: () => void): void {
|
||||
image.onload = () => {
|
||||
if (!complete && !request.closed) {
|
||||
try {
|
||||
loaded()
|
||||
}
|
||||
catch (error) {
|
||||
fail(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
image.onerror = () => fail(new Error(`Image load failed: ${url}`))
|
||||
request.add(() => {
|
||||
image.onload = null
|
||||
image.onerror = null
|
||||
if (!complete)
|
||||
image.removeAttribute('src')
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
const image = new Image()
|
||||
watch(image, () => {
|
||||
if (!scale || scale === 1) {
|
||||
finish(image)
|
||||
return
|
||||
}
|
||||
const canvas = document.createElement('canvas')
|
||||
const context = canvas.getContext('2d')
|
||||
canvas.width = image.width * scale
|
||||
canvas.height = image.height * scale
|
||||
if (!context)
|
||||
throw new TypeError('Canvas 2D context is unavailable')
|
||||
if (complete || request.closed)
|
||||
return
|
||||
context.drawImage(image, 0, 0, canvas.width, canvas.height)
|
||||
if (complete || request.closed)
|
||||
return
|
||||
canvas.toBlob((blob) => {
|
||||
if (complete || request.closed)
|
||||
return
|
||||
try {
|
||||
if (!blob)
|
||||
throw new Error('Unable to encode thumbnail image')
|
||||
const blobUrl = URL.createObjectURL(blob)
|
||||
let revoked = false
|
||||
const revoke = (): undefined => {
|
||||
if (!revoked) {
|
||||
revoked = true
|
||||
URL.revokeObjectURL(blobUrl)
|
||||
}
|
||||
}
|
||||
releaseBlob = owner ? owner.add(revoke) : revoke
|
||||
if (complete || request.closed) {
|
||||
releaseBlob()
|
||||
return
|
||||
}
|
||||
const scaled = new Image()
|
||||
watch(scaled, () => finish(scaled))
|
||||
if (!request.closed)
|
||||
scaled.src = blobUrl
|
||||
}
|
||||
catch (error) {
|
||||
fail(error)
|
||||
}
|
||||
})
|
||||
})
|
||||
if (!request.closed)
|
||||
image.src = url
|
||||
}
|
||||
catch (error) {
|
||||
fail(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Public callers own a scaled result's image.src object URL.
|
||||
export function loadImg(url: string, scale?: number): Promise<HTMLImageElement> {
|
||||
return requestImage(url, scale, undefined)
|
||||
}
|
||||
|
||||
// Internal previews own their result until configuration replacement or destroy.
|
||||
export function loadThumbnailImage(url: string, scale: number | undefined, owner: ResourceScope): Promise<HTMLImageElement | undefined> {
|
||||
return requestImage(url, scale, owner)
|
||||
}
|
||||
Reference in new issue
Block a user