diff --git a/README.md b/README.md index 0774888..2ea056e 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ export interface Options { signal?: AbortSignal; /** - * Throw if a task fails (events will not work if true) @default false + * Throws if a task fails @default false */ throws?: boolean; @@ -369,7 +369,7 @@ task.addEventListener('cycle', (evt) => { ### `BenchEvent` ```ts -export type BenchEvent = Event & { task?: Task }; +export type BenchEvent = Event & { error?: Error; task?: Task }; ``` ### `process.hrtime` diff --git a/src/bench.ts b/src/bench.ts index 8962a53..7d4de86 100644 --- a/src/bench.ts +++ b/src/bench.ts @@ -101,7 +101,7 @@ export default class Bench extends EventTarget { const limit = pLimit(this.threshold); const promises: Promise[] = []; for (const task of this._tasks.values()) { - promises.push(limit(() => task.warmup())); + promises.push(limit(task.warmup.bind(task))); } await Promise.all(promises); } else { @@ -124,7 +124,7 @@ export default class Bench extends EventTarget { const limit = pLimit(this.threshold); const promises: Promise[] = []; for (const task of this._tasks.values()) { - promises.push(limit(() => task.run())); + promises.push(limit(task.run.bind(task))); } values = await Promise.all(promises); } else { diff --git a/src/event.ts b/src/event.ts index 3f496e5..e18c9a1 100644 --- a/src/event.ts +++ b/src/event.ts @@ -14,5 +14,21 @@ function createBenchEvent(eventType: BenchEvents, target?: Task) { return event; } -// eslint-disable-next-line import/prefer-default-export -export { createBenchEvent }; +function createErrorEvent(target: Task, error: Error) { + const event = new Event('error'); + Object.defineProperty(event, 'task', { + value: target, + enumerable: true, + writable: false, + configurable: false, + }); + Object.defineProperty(event, 'error', { + value: error, + enumerable: true, + writable: false, + configurable: false, + }); + return event; +} + +export { createBenchEvent, createErrorEvent }; diff --git a/src/task.ts b/src/task.ts index 49617b6..a7453ef 100644 --- a/src/task.ts +++ b/src/task.ts @@ -1,6 +1,6 @@ import pLimit from 'p-limit'; import type Bench from './bench'; -import { createBenchEvent } from './event'; +import { createBenchEvent, createErrorEvent } from './event'; import type { AddEventListenerOptionsArgument, Fn, @@ -148,11 +148,11 @@ export default class Task extends EventTarget { if (error) { this.setResult({ error }); + this.dispatchEvent(createErrorEvent(this, error)); + this.bench.dispatchEvent(createErrorEvent(this, error)); if (this.bench.throws) { throw error; } - this.dispatchEvent(createBenchEvent('error', this)); - this.bench.dispatchEvent(createBenchEvent('error', this)); } } @@ -217,11 +217,11 @@ export default class Task extends EventTarget { if (error) { this.setResult({ error }); + this.dispatchEvent(createErrorEvent(this, error)); + this.bench.dispatchEvent(createErrorEvent(this, error)); if (this.bench.throws) { throw error; } - this.dispatchEvent(createBenchEvent('error', this)); - this.bench.dispatchEvent(createBenchEvent('error', this)); } this.dispatchEvent(createBenchEvent('cycle', this)); diff --git a/src/types.ts b/src/types.ts index 86fb2a9..24a550c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -269,7 +269,7 @@ export type BenchEvents = export type Hook = (task: Task, mode: 'warmup' | 'run') => void | Promise; -export type BenchEvent = Event & { task?: Task }; +export type BenchEvent = Event & { error?: Error; task?: Task }; export type EventListener = (evt: BenchEvent) => void; @@ -334,7 +334,7 @@ export interface Options { signal?: AbortSignal; /** - * Throw if a task fails (events will not work if true) @default false + * Throws if a task fails @default false */ throws?: boolean; diff --git a/test/index.test.ts b/test/index.test.ts index f784222..b46c22e 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -198,21 +198,23 @@ test('events order at task completion', async () => { test.each(['warmup', 'run'])('%s error event', async (mode) => { const bench = new Bench({ time: 100, warmup: mode === 'warmup' }); - const err = new Error(); + const error = new Error(); bench.add('error', () => { - throw err; + throw error; }); - let taskErr: Error | undefined; + let err: Error | undefined; + let task: Task | undefined; bench.addEventListener('error', (evt) => { - const { task } = evt; - taskErr = task?.result?.error; + const { error: e, task: t } = evt; + err = e; + task = t; }); - await bench.run(); - - expect(taskErr).toStrictEqual(err); + await expect(bench.run()).resolves.toBeDefined(); + expect(err).toStrictEqual(error); + expect(task?.result?.error).toStrictEqual(error); }); test.each(['warmup', 'run'])('%s throws', async (mode) => { @@ -223,12 +225,23 @@ test.each(['warmup', 'run'])('%s throws', async (mode) => { warmup: mode === 'warmup', warmupIterations: iterations, }); - const err = new Error(); + const error = new Error(); bench.add('error', () => { - throw err; + throw error; }); - await expect(() => bench.run()).rejects.toThrowError(err); + + let err: Error | undefined; + let task: Task | undefined; + bench.addEventListener('error', (evt) => { + const { error: e, task: t } = evt; + err = e; + task = t; + }); + + await expect(bench.run()).rejects.toThrowError(error); + expect(err).toStrictEqual(error); + expect(task?.result?.error).toStrictEqual(error); }); test('detect faster task', async () => {