##// END OF EJS Templates
Added Cancellation.combine(...tokens) method to combine multiple cancellation...
cin -
r170:1391543e8282 v1.4.5 default
parent child
Show More
@@ -0,0 +1,41
1 import { ICancellation, IDestroyable } from "./interfaces";
2
3 export class CancellationAggregate implements ICancellation {
4 private readonly _tokens: ICancellation[];
5
6 constructor(tokens: ICancellation[]) {
7 this._tokens = tokens || [];
8 }
9
10 throwIfRequested() {
11 this._tokens.forEach(ct => ct.throwIfRequested());
12 }
13
14 isRequested() {
15 return this._tokens.some(ct => ct.isRequested());
16 }
17 isSupported() {
18 return !!this._tokens.length;
19 }
20 register(cb: (e: any) => void): IDestroyable {
21 let fired = false;
22
23 const once = (e: any) => {
24 if (!fired) {
25 fired = true;
26 destroy();
27 cb(e);
28 }
29 }
30
31 const destroy = () => subscriptions
32 .splice(0,subscriptions.length) // empty array
33 .forEach(subscription => subscription.destroy()); // cleanup
34
35 const subscriptions = this._tokens.map(ct => ct.register(once))
36
37 return {
38 destroy
39 };
40 }
41 }
@@ -1,3 +1,4
1 import { CancellationAggregate } from "./CancellationAggregate";
1 2 import { ICancellation, IDestroyable } from "./interfaces";
2 3 import { argumentNotNull, destroyed } from "./safe";
3 4
@@ -80,4 +81,26 export class Cancellation implements ICa
80 81 return destroyed;
81 82 }
82 83 };
84
85 /**
86 * Combines multiple cancellation tokens to the single aggregated token.
87 *
88 * Aggregated token will be considered as signalled when some tokens are
89 * signalled. The cancellation callback can be registered with the `register`
90 * method, it will be fired once with the first signalled token, all other
91 * tokens will be ignored.
92 *
93 * The tokens which don't support cancellation are filtered out, if there are
94 * no tokens left in the list the method returns `Cancellation.none`.
95 *
96 * @param args The list of cancellation tokens to combine
97 * @returns
98 */
99 static combine(...args: ICancellation[]) {
100 const tokens = args.filter(ct => ct.isSupported());
101 return tokens.length > 1 ?
102 new CancellationAggregate(tokens) :
103 tokens.length == 1 ? tokens[0] :
104 this.none;
83 105 }
106 }
@@ -1,6 +1,5
1 1 import { Cancellation } from "../Cancellation";
2 import { IAsyncComponent, ICancellation, ICancellable, IDestroyable } from "../interfaces";
3 import { destroy } from "../safe";
2 import { IAsyncComponent, ICancellation, ICancellable } from "../interfaces";
4 3
5 4 const noop = () => void (0);
6 5
@@ -13,21 +12,16 export class AsyncComponent implements I
13 12
14 13 runOperation(op: (ct: ICancellation) => any, ct: ICancellation = Cancellation.none) {
15 14 // create inner cancellation bound to the passed cancellation token
16 let h: IDestroyable;
17 15 const inner = new Cancellation(cancel => {
18
19 16 this._cancel = cancel;
20 h = ct.register(cancel);
21 17 });
22 18
23 // TODO create cancellation source here
24 19 const guard = async () => {
25 20 try {
26 await op(inner);
21 return op(Cancellation.combine(ct, inner));
27 22 } finally {
28 23 // after the operation is complete we need to cleanup the
29 24 // resources
30 destroy(h);
31 25 this._cancel = noop;
32 26 }
33 27 };
@@ -1,4 +1,5
1 1 import { Cancellation } from "../Cancellation";
2 import { CancellationAggregate } from "../CancellationAggregate";
2 3 import { delay, notImplemented } from "../safe";
3 4 import { test } from "./TestTraits";
4 5
@@ -86,3 +87,20 test("operation normal flow", async t =>
86 87 clearTimeout(htimeout);
87 88 }
88 89 });
90
91 test("combine cancellations", t => {
92 const ct1 = new Cancellation(cancel => {
93 cancel("cancelled");
94 });
95
96 const ct2 = new Cancellation(() => {});
97
98 const cct1 = Cancellation.combine(Cancellation.none, ct1);
99
100 t.equals(cct1, ct1, "Cancellation.combine should filter out Cancellation.none tokens");
101
102 const cct2 = Cancellation.combine(Cancellation.none, ct1, ct2);
103
104 t.assert(cct2 instanceof CancellationAggregate, "Cancellation.combine should return CancellationAggregate");
105 t.true(cct2.isRequested(), "CancellationAggregate should return isRequested true if any of cancellations is requested");
106 });
General Comments 0
You need to be logged in to leave comments. Login now