|
18 | 18 | import { debugAssert, fail } from './assert';
|
19 | 19 | import { Code, FirestoreError } from './error';
|
20 | 20 | import { logDebug, logError } from './log';
|
21 |
| -import { CancelablePromise, Deferred } from './promise'; |
| 21 | +import { Deferred } from './promise'; |
22 | 22 | import { ExponentialBackoff } from '../remote/backoff';
|
23 | 23 | import { PlatformSupport } from '../platform/platform';
|
24 | 24 | import { isIndexedDbTransactionError } from '../local/simple_db';
|
@@ -86,8 +86,12 @@ export const enum TimerId {
|
86 | 86 | * It is created via DelayedOperation.createAndSchedule().
|
87 | 87 | *
|
88 | 88 | * Supports cancellation (via cancel()) and early execution (via skipDelay()).
|
| 89 | + * |
| 90 | + * Note: We implement `PromiseLike` instead of `Promise`, as the `Promise` type |
| 91 | + * in newer versions of TypeScript defines `finally`, which is not available in |
| 92 | + * IE. |
89 | 93 | */
|
90 |
| -class DelayedOperation<T extends unknown> implements CancelablePromise<T> { |
| 94 | +export class DelayedOperation<T extends unknown> implements PromiseLike<T> { |
91 | 95 | // handle for use with clearTimeout(), or null if the operation has been
|
92 | 96 | // executed or canceled already.
|
93 | 97 | private timerHandle: TimerHandle | null;
|
@@ -175,10 +179,7 @@ class DelayedOperation<T extends unknown> implements CancelablePromise<T> {
|
175 | 179 | }
|
176 | 180 | }
|
177 | 181 |
|
178 |
| - // Promise implementation. |
179 |
| - readonly [Symbol.toStringTag]: 'Promise'; |
180 | 182 | then = this.deferred.promise.then.bind(this.deferred.promise);
|
181 |
| - catch = this.deferred.promise.catch.bind(this.deferred.promise); |
182 | 183 |
|
183 | 184 | private handleDelayElapsed(): void {
|
184 | 185 | this.asyncQueue.enqueueAndForget(() => {
|
@@ -234,10 +235,7 @@ export class AsyncQueue {
|
234 | 235 | // Visibility handler that triggers an immediate retry of all retryable
|
235 | 236 | // operations. Meant to speed up recovery when we regain file system access
|
236 | 237 | // after page comes into foreground.
|
237 |
| - private visibilityHandler = (): void => { |
238 |
| - // eslint-disable-next-line @typescript-eslint/no-floating-promises |
239 |
| - this.runDelayedOperationsEarly(TimerId.AsyncQueueRetry); |
240 |
| - }; |
| 238 | + private visibilityHandler = (): void => this.backoff.skipBackoff(); |
241 | 239 |
|
242 | 240 | constructor() {
|
243 | 241 | const window = PlatformSupport.getPlatform().window;
|
@@ -379,14 +377,14 @@ export class AsyncQueue {
|
379 | 377 |
|
380 | 378 | /**
|
381 | 379 | * Schedules an operation to be queued on the AsyncQueue once the specified
|
382 |
| - * `delayMs` has elapsed. The returned CancelablePromise can be used to cancel |
383 |
| - * the operation prior to its running. |
| 380 | + * `delayMs` has elapsed. The returned DelayedOperation can be used to cancel |
| 381 | + * or fast-forward the operation prior to its running. |
384 | 382 | */
|
385 | 383 | enqueueAfterDelay<T extends unknown>(
|
386 | 384 | timerId: TimerId,
|
387 | 385 | delayMs: number,
|
388 | 386 | op: () => Promise<T>
|
389 |
| - ): CancelablePromise<T> { |
| 387 | + ): DelayedOperation<T> { |
390 | 388 | this.verifyNotFailed();
|
391 | 389 |
|
392 | 390 | debugAssert(
|
@@ -463,21 +461,22 @@ export class AsyncQueue {
|
463 | 461 | }
|
464 | 462 |
|
465 | 463 | /**
|
466 |
| - * Runs some or all delayed operations early. |
| 464 | + * For Tests: Runs some or all delayed operations early. |
467 | 465 | *
|
468 |
| - * @param timerId Delayed operations to run. Pass TimerId.All to run all |
469 |
| - * delayed operations. |
| 466 | + * @param lastTimerId Delayed operations up to and including this TimerId will |
| 467 | + * be drained. Pass TimerId.All to run all delayed operations. |
470 | 468 | * @returns a Promise that resolves once all operations have been run.
|
471 | 469 | */
|
472 |
| - runDelayedOperationsEarly(timerId: TimerId): Promise<void> { |
| 470 | + runAllDelayedOperationsUntil(lastTimerId: TimerId): Promise<void> { |
473 | 471 | // Note that draining may generate more delayed ops, so we do that first.
|
474 | 472 | return this.drain().then(() => {
|
475 | 473 | // Run ops in the same order they'd run if they ran naturally.
|
476 | 474 | this.delayedOperations.sort((a, b) => a.targetTimeMs - b.targetTimeMs);
|
477 | 475 |
|
478 | 476 | for (const op of this.delayedOperations) {
|
479 |
| - if (timerId === TimerId.All || op.timerId === timerId) { |
480 |
| - op.skipDelay(); |
| 477 | + op.skipDelay(); |
| 478 | + if (lastTimerId !== TimerId.All && op.timerId === lastTimerId) { |
| 479 | + break; |
481 | 480 | }
|
482 | 481 | }
|
483 | 482 |
|
|
0 commit comments