1
>
/*---------------------------------------------------------------------------------------------
cancelPreviousCalls.ts
2
>
* Copyright (c) Microsoft Corporation. All rights reserved.
3
>
* Licensed under the MIT License. See License.txt in the project root for license information.
4
>
*--------------------------------------------------------------------------------------------*/
5
>
6
>
import { assertDefined } from '../types.js';
7
>
import { Disposable, DisposableMap } from '../lifecycle.js';
8
>
import { CancellationTokenSource, CancellationToken } from '../cancellation.js';
9
>
10
>
/**
11
>
* Helper type that represents a function that has an optional {@linkcode CancellationToken}
12
>
* argument argument at the end of the arguments list.
13
>
*
14
>
* @typeparam `TFunction` - Type of the function arguments list of which will be extended
15
>
* with an optional {@linkcode CancellationToken} argument.
16
>
*/
17
>
type TWithOptionalCancellationToken<TFunction extends Function> = TFunction extends (...args: infer TArgs) => infer TReturn
18
>
? (...args: [...TArgs, cancellatioNToken?: CancellationToken]) => TReturn
19
>
: never;
20
>
21
>
/**
22
>
* Decorator that provides a mechanism to cancel previous calls of the decorated method
23
>
* by providing a `cancellation token` as the last argument of the method, which gets
24
>
* cancelled immediately on subsequent call of the decorated method.
25
>
*
26
>
* Therefore to use this decorator, the two conditions must be met:
27
>
*
28
>
* - the decorated method must have an *optional* {@linkcode CancellationToken} argument at
29
>
* the end of the arguments list
30
>
* - the object that the decorated method belongs to must implement the {@linkcode Disposable};
31
>
* this requirement comes from the internal implementation of the decorator that
32
>
* creates new resources that need to be eventually disposed by someone
33
>
*
34
>
* @typeparam `TObject` - Object type that the decorated method belongs to.
35
>
* @typeparam `TArgs` - Argument list of the decorated method.
36
>
* @typeparam `TReturn` - Return value type of the decorated method.
37
>
*
38
>
* ### Examples
39
>
*
40
>
* ```typescript
41
>
* // let's say we have a class that implements the `Disposable` interface that we want
42
>
* // to use the decorator on
43
>
* class Example extends Disposable {
44
>
* async doSomethingAsync(arg1: number, arg2: string): Promise<void> {
45
>
* // do something async..
46
>
* await new Promise(resolve => setTimeout(resolve, 1000));
47
>
* }
48
>
* }
49
>
* ```
50
>
*
51
>
* ```typescript
52
>
* // to do that we need to add the `CancellationToken` argument to the end of args list
53
>
* class Example extends Disposable {
54
>
* @cancelPreviousCalls
55
>
* async doSomethingAsync(arg1: number, arg2: string, cancellationToken?: CancellationToken): Promise<void> {
56
>
* console.log(`call with args ${arg1} and ${arg2} initiated`);
57
>
*
58
>
* // the decorator will create the cancellation token automatically
59
>
* assertDefined(
60
>
* cancellationToken,
61
>
* `The method must now have the `CancellationToken` passed to it.`,
62
>
* );
63
>
*
64
>
* cancellationToken.onCancellationRequested(() => {
65
>
* console.log(`call with args ${arg1} and ${arg2} was cancelled`);
66
>
* });
67
>
*
68
>
* // do something async..
69
>
* await new Promise(resolve => setTimeout(resolve, 1000));
70
>
*
71
>
* // check cancellation token state after the async operations
72
>
* console.log(
73
>
* `call with args ${arg1} and ${arg2} completed, canceled?: ${cancellationToken.isCancellationRequested}`,
74
>
* );
75
>
* }
76
>
* }
77
>
*
78
>
* const example = new Example();
79
>
* // call the decorate method first time
80
>
* example.doSomethingAsync(1, 'foo');
81
>
* // wait for 500ms which is less than 1000ms of the async operation in the first call
82
>
* await new Promise(resolve => setTimeout(resolve, 500));
83
>
* // calling the decorate method second time cancels the token passed to the first call
84
>
* example.doSomethingAsync(2, 'bar');
85
>
* ```
86
>
*/
87
>
export function cancelPreviousCalls<
88
TObject extends Disposable,
89
TArgs extends unknown[],