Cancellation.ts
107 lines
| 2.9 KiB
| video/mp2t
|
TypeScriptLexer
|
|
r170 | import { CancellationAggregate } from "./CancellationAggregate"; | ||
|
|
r172 | import { CancelledError } from "./CancelledError"; | ||
|
|
r49 | import { ICancellation, IDestroyable } from "./interfaces"; | ||
|
|
r76 | import { argumentNotNull, destroyed } from "./safe"; | ||
|
|
r49 | |||
| export class Cancellation implements ICancellation { | ||||
| private _reason: any; | ||||
|
|
r115 | private _cbs: Array<(e: any) => void> | undefined; | ||
|
|
r49 | |||
|
|
r76 | constructor(action: (cancel: (e?: any) => void) => void) { | ||
|
|
r49 | argumentNotNull(action, "action"); | ||
| action(this._cancel.bind(this)); | ||||
| } | ||||
| isSupported(): boolean { | ||||
| return true; | ||||
| } | ||||
| throwIfRequested(): void { | ||||
| if (this._reason) | ||||
| throw this._reason; | ||||
| } | ||||
| isRequested(): boolean { | ||||
| return !!this._reason; | ||||
| } | ||||
| register(cb: (e: any) => void): IDestroyable { | ||||
| argumentNotNull(cb, "cb"); | ||||
| if (this._reason) { | ||||
| cb(this._reason); | ||||
| return destroyed; | ||||
| } else { | ||||
| if (!this._cbs) | ||||
| this._cbs = [cb]; | ||||
| else | ||||
| this._cbs.push(cb); | ||||
| const me = this; | ||||
| return { | ||||
| destroy() { | ||||
| me._unregister(cb); | ||||
| } | ||||
| }; | ||||
| } | ||||
| } | ||||
|
|
r115 | private _unregister(cb: any) { | ||
|
|
r49 | if (this._cbs) { | ||
| const i = this._cbs.indexOf(cb); | ||||
| if (i >= 0) | ||||
| this._cbs.splice(i, 1); | ||||
| } | ||||
| } | ||||
|
|
r115 | private _cancel(reason: any) { | ||
|
|
r49 | if (this._reason) | ||
| return; | ||||
|
|
r172 | this._reason = (reason = reason || new CancelledError(undefined, this)); | ||
|
|
r49 | |||
| if (this._cbs) { | ||||
| this._cbs.forEach(cb => cb(reason)); | ||||
|
|
r115 | this._cbs = undefined; | ||
|
|
r49 | } | ||
| } | ||||
| static readonly none: ICancellation = { | ||||
| isSupported(): boolean { | ||||
| return false; | ||||
| }, | ||||
| throwIfRequested(): void { | ||||
| }, | ||||
| isRequested(): boolean { | ||||
| return false; | ||||
| }, | ||||
| register(_cb: (e: any) => void): IDestroyable { | ||||
| return destroyed; | ||||
| } | ||||
| }; | ||||
|
|
r170 | |||
| /** | ||||
| * Combines multiple cancellation tokens to the single aggregated token. | ||||
|
|
r172 | * | ||
|
|
r170 | * Aggregated token will be considered as signalled when some tokens are | ||
| * signalled. The cancellation callback can be registered with the `register` | ||||
| * method, it will be fired once with the first signalled token, all other | ||||
| * tokens will be ignored. | ||||
|
|
r172 | * | ||
|
|
r170 | * The tokens which don't support cancellation are filtered out, if there are | ||
| * no tokens left in the list the method returns `Cancellation.none`. | ||||
|
|
r172 | * | ||
|
|
r170 | * @param args The list of cancellation tokens to combine | ||
|
|
r172 | * @returns Aggregated cancellation token | ||
|
|
r170 | */ | ||
| static combine(...args: ICancellation[]) { | ||||
| const tokens = args.filter(ct => ct.isSupported()); | ||||
| return tokens.length > 1 ? | ||||
| new CancellationAggregate(tokens) : | ||||
|
|
r172 | tokens.length === 1 ? tokens[0] : | ||
|
|
r170 | this.none; | ||
| } | ||||
|
|
r49 | } | ||
