microsoft/vscode-react-native

Public

mirrored from https://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
1.8.1

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

src/common/node/promise.ts

234lines · modecode

1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for details.
3
4import { CancellationTokenSource, Disposable } from "vscode";
5
6/**
7 * Utilities for working with promises.
8 */
9export class PromiseUtil {
10 public static async forEach<T>(
11 sources: T[],
12 promiseGenerator: (source: T) => Promise<void>,
13 ): Promise<void> {
14 await Promise.all(
15 sources.map(source => {
16 return promiseGenerator(source);
17 }),
18 );
19 }
20 /**
21 * Retries an operation a given number of times. For each retry, a condition is checked.
22 * If the condition is not satisfied after the maximum number of retries, and error is thrown.
23 * Otherwise, the result of the operation is returned once the condition is satisfied.
24 *
25 * @param operation - the function to execute.
26 * @param condition - the condition to check between iterations.
27 * @param maxRetries - the maximum number of retries.
28 * @param delay - time between iterations, in milliseconds.
29 * @param failure - error description.
30 */
31 public static retryAsync<T>(
32 operation: () => Promise<T>,
33 condition: (result: T) => boolean | Promise<boolean>,
34 maxRetries: number,
35 delay: number,
36 failure: string,
37 cancellationTokenSource?: CancellationTokenSource,
38 ): Promise<T> {
39 return this.retryAsyncIteration(
40 operation,
41 condition,
42 maxRetries,
43 0,
44 delay,
45 failure,
46 cancellationTokenSource,
47 );
48 }
49
50 public static async reduce<T>(
51 sources: T[] | Promise<T[]>,
52 generateAsyncOperation: (value: T) => Promise<void>,
53 ): Promise<void> {
54 let arraySources: T[];
55 if (sources instanceof Promise) {
56 arraySources = await sources;
57 } else {
58 arraySources = sources;
59 }
60
61 return arraySources.reduce(async (previousReduction: Promise<void>, newSource: T) => {
62 await previousReduction;
63 return generateAsyncOperation(newSource);
64 }, Promise.resolve());
65 }
66
67 public static async delay(duration: number): Promise<void> {
68 return new Promise<void>(resolve => setTimeout(resolve, duration));
69 }
70
71 public static waitUntil<T>(
72 condition: () => Promise<T | null> | T | null,
73 interval: number = 1000,
74 timeout?: number,
75 ): Promise<T | null> {
76 return new Promise(async resolve => {
77 let rejectTimeout: NodeJS.Timeout | undefined;
78 let сheckInterval: NodeJS.Timeout | undefined;
79
80 if (timeout) {
81 rejectTimeout = setTimeout(() => {
82 cleanup();
83 resolve(null);
84 }, timeout);
85 }
86
87 const cleanup = () => {
88 if (rejectTimeout) {
89 clearTimeout(rejectTimeout);
90 }
91 if (сheckInterval) {
92 clearInterval(сheckInterval);
93 }
94 };
95
96 const tryToResolve = async (): Promise<boolean> => {
97 const result = await condition();
98 if (result) {
99 cleanup();
100 resolve(result);
101 }
102 return !!result;
103 };
104
105 const resolved = await tryToResolve();
106 if (resolved) {
107 return;
108 }
109
110 сheckInterval = setInterval(async () => {
111 await tryToResolve();
112 }, interval);
113 });
114 }
115
116 public static promiseCacheDecorator<T>(
117 func: (...args: any[]) => Promise<T>,
118 context: Record<string, any> | null = null,
119 ): (...args: any[]) => Promise<T> {
120 let promise: Promise<T>;
121 return (...args: any[]): Promise<T> => {
122 if (!promise) {
123 promise = func.apply(context, args);
124 }
125 return promise;
126 };
127 }
128
129 private static async retryAsyncIteration<T>(
130 operation: () => Promise<T>,
131 condition: (result: T) => boolean | Promise<boolean>,
132 maxRetries: number,
133 iteration: number,
134 delay: number,
135 failure: string,
136 cancellationTokenSource?: CancellationTokenSource,
137 ): Promise<T> {
138 const result = await operation();
139 const conditionResult = await condition(result);
140 if (conditionResult) {
141 return result;
142 }
143
144 if (
145 iteration < maxRetries &&
146 !(cancellationTokenSource && cancellationTokenSource.token.isCancellationRequested)
147 ) {
148 await PromiseUtil.delay(delay);
149 return this.retryAsyncIteration(
150 operation,
151 condition,
152 maxRetries,
153 iteration + 1,
154 delay,
155 failure,
156 cancellationTokenSource,
157 );
158 }
159
160 throw new Error(failure);
161 }
162}
163
164export class Delayer<T> implements Disposable {
165 private timeout: any;
166 private completionPromise: Promise<any> | null;
167 private doResolve: ((value?: any | Promise<any>) => void) | null;
168 private doReject: ((err: any) => void) | null;
169 private task: { (): T | Promise<T> } | null;
170
171 constructor() {
172 this.timeout = null;
173 this.completionPromise = null;
174 this.doResolve = null;
175 this.doReject = null;
176 this.task = null;
177 }
178
179 public runWihtDelay(task: { (): T | Promise<T> }, delay: number): Promise<T> {
180 this.task = task;
181 this.cancelTimeout();
182
183 if (!this.completionPromise) {
184 this.completionPromise = new Promise((resolve, reject) => {
185 this.doResolve = resolve;
186 this.doReject = reject;
187 }).then(() => {
188 this.completionPromise = null;
189 this.doResolve = null;
190 if (this.task) {
191 const task = this.task;
192 this.task = null;
193 return task();
194 }
195 return undefined;
196 });
197 }
198
199 this.timeout = setTimeout(() => {
200 this.timeout = null;
201 if (this.doResolve) {
202 this.doResolve(null);
203 }
204 }, delay);
205
206 return this.completionPromise;
207 }
208
209 public isRunning(): boolean {
210 return this.timeout !== null;
211 }
212
213 public cancel(): void {
214 this.cancelTimeout();
215
216 if (this.completionPromise) {
217 if (this.doReject) {
218 this.doReject(new Error("Canceled"));
219 }
220 this.completionPromise = null;
221 }
222 }
223
224 public dispose(): void {
225 this.cancel();
226 }
227
228 private cancelTimeout(): void {
229 if (this.timeout !== null) {
230 clearTimeout(this.timeout);
231 this.timeout = null;
232 }
233 }
234}
235