diff --git a/src/context.ts b/src/context.ts index 23b483fe..45966a7b 100644 --- a/src/context.ts +++ b/src/context.ts @@ -22,7 +22,7 @@ import { Callback } from "@/emitter/types.js"; import { createNonOverridableObject } from "@/internals/helpers/object.js"; import { registerSignals } from "@/internals/helpers/cancellation.js"; import { Serializable } from "@/internals/serializable.js"; -import { LazyPromise } from "@/internals/helpers/promise.js"; +import { executeSequentially, LazyPromise } from "@/internals/helpers/promise.js"; import { FrameworkError } from "@/errors.js"; import { shallowCopy } from "@/serializer/utils.js"; @@ -41,6 +41,8 @@ export type GetRunContext = T extends RunInstance ? RunContext export type GetRunInstance = T extends RunInstance ? P : never; export class Run extends LazyPromise { + protected readonly tasks: (() => Promise)[] = []; + constructor( handler: () => Promise, protected readonly runContext: GetRunContext, @@ -51,20 +53,27 @@ export class Run extends LazyPromise { readonly [Symbol.toStringTag] = "Promise"; observe(fn: (emitter: Emitter>) => void) { - fn(this.runContext.emitter); + this.tasks.push(async () => fn(this.runContext.emitter)); return this; } context(value: object) { - Object.assign(this.runContext.context, value); - Object.assign(this.runContext.emitter.context, value); + this.tasks.push(async () => { + Object.assign(this.runContext.context, value); + Object.assign(this.runContext.emitter.context, value); + }); return this; } middleware(fn: (context: GetRunContext) => void) { - fn(this.runContext); + this.tasks.push(async () => fn(this.runContext)); return this; } + + protected async before(): Promise { + await super.before(); + await executeSequentially(this.tasks.splice(0, Infinity)); + } } export interface RunContextInput

{ diff --git a/src/internals/helpers/promise.ts b/src/internals/helpers/promise.ts index 9b599e2d..26ec8192 100644 --- a/src/internals/helpers/promise.ts +++ b/src/internals/helpers/promise.ts @@ -112,21 +112,23 @@ export class LazyPromise implements Promise { readonly [Symbol.toStringTag] = "Promise"; + protected async before(): Promise {} + then( onfulfilled?: ((value: R) => PromiseLike | TResult1) | undefined | null, onrejected?: ((reason: any) => PromiseLike | TResult2) | undefined | null, ): Promise { - return this.handler().then(onfulfilled).catch(onrejected); + return this.before().then(this.handler).then(onfulfilled).catch(onrejected); } catch( onrejected?: ((reason: any) => PromiseLike | TResult) | undefined | null, ): Promise { - return this.handler().then(undefined).catch(onrejected); + return this.before().then(this.handler).then(undefined).catch(onrejected); } finally(onfinally?: (() => void) | undefined | null): Promise { - return this.handler().finally(onfinally); + return this.before().then(this.handler).finally(onfinally); } } @@ -152,3 +154,9 @@ export async function signalRace( .finally(() => signal?.removeEventListener?.("abort", signalFn)); }); } + +export async function executeSequentially(tasks: (() => Promise)[]): Promise { + for (const task of tasks) { + await task(); + } +}