From 56ec3c47108f66ef970ad619ba7f15e9c27a735b Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Thu, 16 Dec 2021 14:40:05 +0100 Subject: [PATCH 1/2] feat(syncpromise): trim down SyncPromise --- packages/utils/src/promisebuffer.ts | 33 ++++++--- packages/utils/src/syncpromise.ts | 106 +++++++--------------------- 2 files changed, 52 insertions(+), 87 deletions(-) diff --git a/packages/utils/src/promisebuffer.ts b/packages/utils/src/promisebuffer.ts index ff81d8dcddd8..94c4a8f48d00 100644 --- a/packages/utils/src/promisebuffer.ts +++ b/packages/utils/src/promisebuffer.ts @@ -1,6 +1,27 @@ import { SentryError } from './error'; import { SyncPromise } from './syncpromise'; +function allPromises(collection: Array>): PromiseLike { + return new SyncPromise((resolve, reject) => { + if (collection.length === 0) { + resolve(null); + return; + } + + let counter = collection.length; + collection.forEach(item => { + void SyncPromise.resolve(item) + .then(() => { + // eslint-disable-next-line no-plusplus + if (--counter === 0) { + resolve(null); + } + }) + .then(null, reject); + }); + }); +} + /** A simple queue that holds promises. */ export class PromiseBuffer { /** Internal set of queued Promises */ @@ -85,14 +106,10 @@ export class PromiseBuffer { }, timeout); // if all promises resolve in time, cancel the timer and resolve to `true` - void SyncPromise.all(this._buffer) - .then(() => { - clearTimeout(capturedSetTimeout); - resolve(true); - }) - .then(null, () => { - resolve(true); - }); + void allPromises(this._buffer).then(() => { + clearTimeout(capturedSetTimeout); + resolve(true); + }); }); } } diff --git a/packages/utils/src/syncpromise.ts b/packages/utils/src/syncpromise.ts index 3102a3b67d2b..316085441c90 100644 --- a/packages/utils/src/syncpromise.ts +++ b/packages/utils/src/syncpromise.ts @@ -7,11 +7,11 @@ import { isThenable } from './is'; /** SyncPromise internal states */ const enum States { /** Pending */ - PENDING = 'PENDING', + PENDING = 0, /** Resolved / OK */ - RESOLVED = 'RESOLVED', + RESOLVED = 1, /** Rejected / Error */ - REJECTED = 'REJECTED', + REJECTED = 2, } /** @@ -20,11 +20,7 @@ const enum States { */ class SyncPromise implements PromiseLike { private _state: States = States.PENDING; - private _handlers: Array<{ - done: boolean; - onfulfilled?: ((value: T) => T | PromiseLike) | null; - onrejected?: ((reason: any) => any) | null; - }> = []; + private _handlers: Array<[boolean, (value: T) => T | PromiseLike, (reason: any) => any]> = []; private _value: any; public constructor( @@ -51,75 +47,38 @@ class SyncPromise implements PromiseLike { }); } - /** JSDoc */ - public static all(collection: Array>): PromiseLike { - return new SyncPromise((resolve, reject) => { - if (!Array.isArray(collection)) { - reject(new TypeError(`Promise.all requires an array as input.`)); - return; - } - - if (collection.length === 0) { - resolve([]); - return; - } - - let counter = collection.length; - const resolvedCollection: U[] = []; - - collection.forEach((item, index) => { - void SyncPromise.resolve(item) - .then(value => { - resolvedCollection[index] = value; - counter -= 1; - - if (counter !== 0) { - return; - } - resolve(resolvedCollection); - }) - .then(null, reject); - }); - }); - } - /** JSDoc */ public then( onfulfilled?: ((value: T) => TResult1 | PromiseLike) | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null, ): PromiseLike { return new SyncPromise((resolve, reject) => { - this._attachHandler({ - done: false, - onfulfilled: result => { + this._attachHandler( + result => { if (!onfulfilled) { // TODO: ¯\_(ツ)_/¯ // TODO: FIXME resolve(result as any); - return; - } - try { - resolve(onfulfilled(result)); - return; - } catch (e) { - reject(e); - return; + } else { + try { + resolve(onfulfilled(result)); + } catch (e) { + reject(e); + } } }, - onrejected: reason => { + reason => { if (!onrejected) { reject(reason); - return; - } - try { - resolve(onrejected(reason)); - return; - } catch (e) { - reject(e); - return; + } else { + try { + resolve(onrejected(reason)); + } catch (e) { + reject(e); + } } }, - }); + ); }); } @@ -196,15 +155,8 @@ class SyncPromise implements PromiseLike { // TODO: FIXME /** JSDoc */ - private readonly _attachHandler = (handler: { - /** JSDoc */ - done: boolean; - /** JSDoc */ - onfulfilled?(value: T): any; - /** JSDoc */ - onrejected?(reason: any): any; - }) => { - this._handlers = this._handlers.concat(handler); + private readonly _attachHandler = (onfulfilled: (value: T) => any, onrejected: (reason: any) => any) => { + this._handlers.push([false, onfulfilled, onrejected]); this._executeHandlers(); }; @@ -218,24 +170,20 @@ class SyncPromise implements PromiseLike { this._handlers = []; cachedHandlers.forEach(handler => { - if (handler.done) { + if (handler[0]) { return; } if (this._state === States.RESOLVED) { - if (handler.onfulfilled) { - // eslint-disable-next-line @typescript-eslint/no-floating-promises - handler.onfulfilled((this._value as unknown) as any); - } + // eslint-disable-next-line @typescript-eslint/no-floating-promises + handler[1]((this._value as unknown) as any); } if (this._state === States.REJECTED) { - if (handler.onrejected) { - handler.onrejected(this._value); - } + handler[2](this._value); } - handler.done = true; + handler[0] = true; }); }; } From 1ce317b5e0605f3c3c77a986fe39c464cd2da168 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Thu, 16 Dec 2021 14:52:58 +0100 Subject: [PATCH 2/2] ref: more trimming on the sync promise --- packages/utils/src/syncpromise.ts | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/packages/utils/src/syncpromise.ts b/packages/utils/src/syncpromise.ts index 316085441c90..4e5e798e94e4 100644 --- a/packages/utils/src/syncpromise.ts +++ b/packages/utils/src/syncpromise.ts @@ -20,7 +20,7 @@ const enum States { */ class SyncPromise implements PromiseLike { private _state: States = States.PENDING; - private _handlers: Array<[boolean, (value: T) => T | PromiseLike, (reason: any) => any]> = []; + private _handlers: Array<[boolean, (value: T) => void, (reason: any) => any]> = []; private _value: any; public constructor( @@ -53,7 +53,8 @@ class SyncPromise implements PromiseLike { onrejected?: ((reason: any) => TResult2 | PromiseLike) | null, ): PromiseLike { return new SyncPromise((resolve, reject) => { - this._attachHandler( + this._handlers.push([ + false, result => { if (!onfulfilled) { // TODO: ¯\_(ツ)_/¯ @@ -78,7 +79,8 @@ class SyncPromise implements PromiseLike { } } }, - ); + ]); + this._executeHandlers(); }); } @@ -121,11 +123,6 @@ class SyncPromise implements PromiseLike { }); } - /** JSDoc */ - public toString(): string { - return '[object SyncPromise]'; - } - /** JSDoc */ private readonly _resolve = (value?: T | PromiseLike | null) => { this._setResult(States.RESOLVED, value); @@ -153,13 +150,6 @@ class SyncPromise implements PromiseLike { this._executeHandlers(); }; - // TODO: FIXME - /** JSDoc */ - private readonly _attachHandler = (onfulfilled: (value: T) => any, onrejected: (reason: any) => any) => { - this._handlers.push([false, onfulfilled, onrejected]); - this._executeHandlers(); - }; - /** JSDoc */ private readonly _executeHandlers = () => { if (this._state === States.PENDING) {