Skip to content

Commit

Permalink
Fix potential unhandled rejections in StrategyHandler.doneWaiting
Browse files Browse the repository at this point in the history
doneWaiting throws on the first rejected promise that it encounters.  This means that subsequent rejected promises may result in unhandled rejection errors.

Fixes GoogleChrome#3171
  • Loading branch information
joshkel committed Feb 1, 2023
1 parent 9416404 commit 37b7347
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 3 deletions.
40 changes: 40 additions & 0 deletions packages/workbox-core/src/_private/allSettled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
export interface PromiseResolution<T> {
status: 'fulfilled';
value: T;
}

export interface PromiseRejection {
status: 'rejected';
reason: unknown;
}

export type PromiseResult<T> = PromiseResolution<T> | PromiseRejection;

/**
* Promise.allSettled polyfill based on
*
* https://github.com/es-shims/Promise.allSettled/blob/main/implementation.js
*
* which is (c) 2019 Jordan Harband and used under the terms of the MIT license.
*/
export function allSettled<T>(
iterable: Iterable<Promise<T>>,
): Promise<PromiseResult<T>[]> {
const values = Array.from(iterable);
return Promise.all(
values.map(function (item) {
const onFulfill = function (value: T) {
return {status: 'fulfilled' as const, value: value};
};
const onReject = function (reason: unknown) {
return {status: 'rejected' as const, reason: reason};
};
const itemPromise = Promise.resolve(item);
try {
return itemPromise.then(onFulfill, onReject);
} catch (e) {
return Promise.reject(e);
}
}),
);
}
14 changes: 11 additions & 3 deletions packages/workbox-strategies/src/StrategyHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
https://opensource.org/licenses/MIT.
*/

import {
allSettled,
PromiseRejection,
} from 'workbox-core/_private/allSettled.js';
import {assert} from 'workbox-core/_private/assert.js';
import {cacheMatchIgnoreParams} from 'workbox-core/_private/cacheMatchIgnoreParams.js';
import {Deferred} from 'workbox-core/_private/Deferred.js';
Expand Down Expand Up @@ -560,9 +564,13 @@ class StrategyHandler {
* prior to your work completing.
*/
async doneWaiting(): Promise<void> {
let promise;
while ((promise = this._extendLifetimePromises.shift())) {
await promise;
while (this._extendLifetimePromises.length) {
const promises = this._extendLifetimePromises.splice(0);
const result = await allSettled(promises);
const firstRejection = result.find((i) => i.status === 'rejected');
if (firstRejection) {
throw (firstRejection as PromiseRejection).reason;
}
}
}

Expand Down

0 comments on commit 37b7347

Please sign in to comment.