Skip to content

Commit 04d9bc0

Browse files
committed
fix(DisposeAggregator)!: all targets get disposed even if one throws
BREAKING CHANGE: when a target throws an error when `DisposeAggregator` attempts to dispose it, then the error will be thrown, but the rest of the targets will continue to get disposed
1 parent afaf97b commit 04d9bc0

1 file changed

Lines changed: 38 additions & 14 deletions

File tree

‎src/DisposeAggregator.ts‎

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {DisposedError} from "./DisposedError.js";
2020
* ```
2121
*/
2222
export class DisposeAggregator {
23-
/** @internal */ private readonly _targets: DisposeAggregatorTarget[] = [];
23+
/** @internal */ private _targets: DisposeAggregatorTarget[] = [];
2424
/** @internal */ private _disposed: boolean = false;
2525

2626
public constructor() {
@@ -42,28 +42,52 @@ export class DisposeAggregator {
4242

4343
/**
4444
* Disposes all the targets that have been added and clears the list of targets.
45+
*
46+
* After all the targets have been disposed, if any throws an error,
47+
* then the error from the first such target will be thrown.
4548
*/
4649
public dispose(): void {
4750
if (this._disposed)
4851
return;
4952

50-
while (this._targets.length > 0) {
51-
let disposeTarget = this._targets.shift();
53+
this._disposed = true;
54+
55+
let firstError: unknown;
56+
let hasError: boolean = false;
57+
58+
const targets: (DisposeAggregatorTarget | null)[] = this._targets;
59+
this._targets = [];
60+
for (let i = 0; i < targets.length; i++) {
61+
let disposeTarget = targets[i];
62+
targets[i] = null;
5263

53-
if (typeof WeakRef !== "undefined" && disposeTarget instanceof WeakRef)
54-
disposeTarget = disposeTarget.deref();
64+
try {
65+
if (typeof WeakRef !== "undefined" && disposeTarget instanceof WeakRef)
66+
disposeTarget = disposeTarget.deref();
5567

56-
if (disposeTarget == null)
57-
continue;
58-
else if (disposeTarget instanceof Function)
59-
disposeTarget();
60-
else if (Symbol.dispose != null && Symbol.dispose in disposeTarget && disposeTarget[Symbol.dispose] instanceof Function)
61-
disposeTarget[Symbol.dispose]();
62-
else if ("dispose" in disposeTarget && disposeTarget.dispose instanceof Function)
63-
disposeTarget.dispose();
68+
if (disposeTarget == null || disposeTarget === this)
69+
continue;
70+
else if (typeof disposeTarget === "function") {
71+
if (disposeTarget === this.dispose || disposeTarget === this[Symbol.dispose])
72+
continue;
73+
74+
disposeTarget();
75+
} else if (Symbol.dispose != null && Symbol.dispose in disposeTarget && typeof disposeTarget[Symbol.dispose] === "function")
76+
disposeTarget[Symbol.dispose]();
77+
else if ("dispose" in disposeTarget && typeof disposeTarget.dispose === "function")
78+
disposeTarget.dispose();
79+
} catch (err) {
80+
if (!hasError) {
81+
firstError = err;
82+
hasError = true;
83+
}
84+
}
6485
}
6586

66-
this._disposed = true;
87+
targets.length = 0;
88+
89+
if (hasError)
90+
throw firstError;
6791
}
6892

6993
public [Symbol.dispose](): void {

0 commit comments

Comments
 (0)