| 181 | * } |
| 182 | */ |
| 183 | export class Throttler implements IDisposable { |
| 184 | |
| 185 | private activePromise: Promise<any> | null; |
| 186 | private queuedPromise: Promise<any> | null; |
| 187 | private queuedPromiseFactory: ITask<Promise<any>> | null; |
| 188 | |
| 189 | private isDisposed = false; |
| 190 | |
| 191 | constructor() { |
| 192 | this.activePromise = null; |
| 193 | this.queuedPromise = null; |
| 194 | this.queuedPromiseFactory = null; |
| 195 | } |
| 196 | |
| 197 | queue<T>(promiseFactory: ITask<Promise<T>>): Promise<T> { |
| 198 | if (this.isDisposed) { |
| 199 | return Promise.reject(new Error('Throttler is disposed')); |
| 200 | } |
| 201 | |
| 202 | if (this.activePromise) { |
| 203 | this.queuedPromiseFactory = promiseFactory; |
| 204 | |
| 205 | if (!this.queuedPromise) { |
| 206 | const onComplete = () => { |
| 207 | this.queuedPromise = null; |
| 208 | |
| 209 | if (this.isDisposed) { |
| 210 | return; |
| 211 | } |
| 212 | |
| 213 | const result = this.queue(this.queuedPromiseFactory!); |
| 214 | this.queuedPromiseFactory = null; |
| 215 | |
| 216 | return result; |
| 217 | }; |
| 218 | |
| 219 | this.queuedPromise = new Promise(resolve => { |
| 220 | this.activePromise!.then(onComplete, onComplete).then(resolve); |
| 221 | }); |
| 222 | } |
| 223 | |
| 224 | return new Promise((resolve, reject) => { |
| 225 | this.queuedPromise!.then(resolve, reject); |
| 226 | }); |
| 227 | } |
| 228 | |
| 229 | this.activePromise = promiseFactory(); |
| 230 | |
| 231 | return new Promise((resolve, reject) => { |
| 232 | this.activePromise!.then((result: T) => { |
| 233 | this.activePromise = null; |
| 234 | resolve(result); |
| 235 | }, (err: unknown) => { |
| 236 | this.activePromise = null; |
| 237 | reject(err); |
| 238 | }); |
| 239 | }); |
| 240 | } |
nothing calls this directly
no outgoing calls
no test coverage detected