Files
ArtPlayer/packages/artplayer/src/lifecycle/scope.ts
T

66 lines
1.4 KiB
TypeScript

export type Cleanup = () => undefined
export class ResourceCleanupError extends Error {
constructor(readonly errors: unknown[]) {
super('Failed to release ArtPlayer resources')
this.name = 'ResourceCleanupError'
}
}
export default class ResourceScope {
private cleanups = new Set<() => void>()
private disposed = false
get closed(): boolean {
return this.disposed
}
add(cleanup: Cleanup): () => void {
let active = true
const release = () => {
if (!active)
return
active = false
this.cleanups.delete(release)
cleanup()
}
if (this.closed)
release()
else
this.cleanups.add(release)
return release
}
child(): ResourceScope {
const child = new ResourceScope()
const release = this.add(() => {
child.dispose()
})
child.add(() => {
release()
})
return child
}
dispose(): void {
if (this.closed)
return
this.disposed = true
const errors: unknown[] = []
// Unwind dependencies; release removes each registration before invoking it.
for (const release of Array.from(this.cleanups).reverse()) {
try {
release()
}
catch (error) {
if (error instanceof ResourceCleanupError)
errors.push(...error.errors)
else
errors.push(error)
}
}
if (errors.length)
throw new ResourceCleanupError(errors)
}
}