@difizen/mana-common
Version:
50 lines (48 loc) • 1.48 kB
text/typescript
import type { Emitter } from './event';
export type WaitUntilEvent = {
/**
* Allows to pause the event loop until the provided thenable resolved.
* *Note:* It can only be called during event dispatch and not in an asynchronous manner
* @param thenable A thenable that delays execution.
*/
waitUntil?: (thenable: Promise<any>) => void;
};
export namespace WaitUntilEvent {
/**
* Fire all listeners in the same tick.
* Use `AsyncEmitter.fire` to fire listeners async one after another.
*/
export async function fire<T extends WaitUntilEvent>(
emitter: Emitter<T>,
event: Omit<T, 'waitUntil'>,
timeout: number | undefined = undefined,
): Promise<void> {
const waitables: Promise<void>[] = [];
const asyncEvent = Object.assign(event, {
waitUntil: (thenable: Promise<any>) => {
if (Object.isFrozen(waitables)) {
throw new Error('waitUntil cannot be called asynchronously.');
}
waitables.push(thenable);
},
}) as T;
try {
emitter.fire(asyncEvent);
// Asynchronous calls to `waitUntil` should fail.
Object.freeze(waitables);
} finally {
delete asyncEvent.waitUntil;
}
if (!waitables.length) {
return;
}
if (timeout !== undefined) {
await Promise.race([
Promise.all(waitables),
new Promise((resolve) => setTimeout(resolve, timeout)),
]);
} else {
await Promise.all(waitables);
}
}
}