| 153 | * Provides the ability to chain promises. |
| 154 | */ |
| 155 | export class PromiseChain { |
| 156 | private currentPromise: Promise<void | undefined> = Promise.resolve(undefined); |
| 157 | /** |
| 158 | * Chain the provided promise after all previous promises have successfully completed. |
| 159 | * If the previously chained promises have failed, then this call will fail. |
| 160 | */ |
| 161 | public async chain<T>(promise: () => Promise<T>): Promise<T> { |
| 162 | const deferred = createDeferred<T>(); |
| 163 | const previousPromise = this.currentPromise; |
| 164 | this.currentPromise = this.currentPromise.then(async () => { |
| 165 | try { |
| 166 | const result = await promise(); |
| 167 | deferred.resolve(result); |
| 168 | } catch (ex) { |
| 169 | deferred.reject(ex); |
| 170 | throw ex; |
| 171 | } |
| 172 | }); |
| 173 | // Wait for previous promises to complete. |
| 174 | await previousPromise; |
| 175 | return deferred.promise; |
| 176 | } |
| 177 | /** |
| 178 | * Chain the provided promise after all previous promises have completed (ignoring errors in previous promises). |
| 179 | */ |
| 180 | public chainFinally<T>(promise: () => Promise<T>): Promise<T> { |
| 181 | const deferred = createDeferred<T>(); |
| 182 | this.currentPromise = this.currentPromise.finally(() => |
| 183 | promise() |
| 184 | .then((result) => deferred.resolve(result)) |
| 185 | .catch((ex) => deferred.reject(ex)) |
| 186 | ); |
| 187 | return deferred.promise; |
| 188 | } |
| 189 | } |
| 190 | |
| 191 | export interface ITask<T> { |
| 192 | (): T; |