@bquery/bquery 1.8.2 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +255 -27
- package/dist/{a11y-DVBCy09c.js → a11y-DG2i4iZN.js} +3 -3
- package/dist/{a11y-DVBCy09c.js.map → a11y-DG2i4iZN.js.map} +1 -1
- package/dist/a11y.es.mjs +1 -1
- package/dist/{component-L3-JfOFz.js → component-DRotf1hl.js} +19 -18
- package/dist/{component-L3-JfOFz.js.map → component-DRotf1hl.js.map} +1 -1
- package/dist/component.es.mjs +1 -1
- package/dist/concurrency/errors.d.ts +29 -0
- package/dist/concurrency/errors.d.ts.map +1 -0
- package/dist/concurrency/high-level.d.ts +85 -0
- package/dist/concurrency/high-level.d.ts.map +1 -0
- package/dist/concurrency/index.d.ts +19 -0
- package/dist/concurrency/index.d.ts.map +1 -0
- package/dist/concurrency/internal.d.ts +26 -0
- package/dist/concurrency/internal.d.ts.map +1 -0
- package/dist/concurrency/pipeline.d.ts +30 -0
- package/dist/concurrency/pipeline.d.ts.map +1 -0
- package/dist/concurrency/pool.d.ts +48 -0
- package/dist/concurrency/pool.d.ts.map +1 -0
- package/dist/concurrency/reactive.d.ts +107 -0
- package/dist/concurrency/reactive.d.ts.map +1 -0
- package/dist/concurrency/rpc.d.ts +46 -0
- package/dist/concurrency/rpc.d.ts.map +1 -0
- package/dist/concurrency/support.d.ts +23 -0
- package/dist/concurrency/support.d.ts.map +1 -0
- package/dist/concurrency/task.d.ts +31 -0
- package/dist/concurrency/task.d.ts.map +1 -0
- package/dist/concurrency/types.d.ts +343 -0
- package/dist/concurrency/types.d.ts.map +1 -0
- package/dist/concurrency-BU1wPEsZ.js +826 -0
- package/dist/concurrency-BU1wPEsZ.js.map +1 -0
- package/dist/concurrency.es.mjs +29 -0
- package/dist/{constraints-D5RHQLmP.js → constraints-CqjhmpZC.js} +1 -1
- package/dist/{constraints-D5RHQLmP.js.map → constraints-CqjhmpZC.js.map} +1 -1
- package/dist/core-CongXJuo.js +87 -0
- package/dist/core-CongXJuo.js.map +1 -0
- package/dist/{custom-directives-Dr4C5lVV.js → custom-directives-BjFzFhuf.js} +1 -1
- package/dist/{custom-directives-Dr4C5lVV.js.map → custom-directives-BjFzFhuf.js.map} +1 -1
- package/dist/{devtools-BhB2iDPT.js → devtools-C5FExMwv.js} +2 -2
- package/dist/{devtools-BhB2iDPT.js.map → devtools-C5FExMwv.js.map} +1 -1
- package/dist/devtools.es.mjs +1 -1
- package/dist/{dnd-NwZBYh4l.js → dnd-BAqzPlSo.js} +1 -1
- package/dist/{dnd-NwZBYh4l.js.map → dnd-BAqzPlSo.js.map} +1 -1
- package/dist/dnd.es.mjs +1 -1
- package/dist/effect-Cc51IH91.js +87 -0
- package/dist/effect-Cc51IH91.js.map +1 -0
- package/dist/{env-CTdvLaH2.js → env-PvwYHnJq.js} +1 -1
- package/dist/{env-CTdvLaH2.js.map → env-PvwYHnJq.js.map} +1 -1
- package/dist/{forms-UcRHsYxC.js → forms-Dx1Scvh0.js} +30 -29
- package/dist/{forms-UcRHsYxC.js.map → forms-Dx1Scvh0.js.map} +1 -1
- package/dist/forms.es.mjs +1 -1
- package/dist/full.d.ts +6 -4
- package/dist/full.d.ts.map +1 -1
- package/dist/full.es.mjs +240 -206
- package/dist/full.iife.js +117 -33
- package/dist/full.iife.js.map +1 -1
- package/dist/full.umd.js +117 -33
- package/dist/full.umd.js.map +1 -1
- package/dist/{i18n-kuF6Ekj6.js → i18n-Cazyk9RD.js} +3 -3
- package/dist/{i18n-kuF6Ekj6.js.map → i18n-Cazyk9RD.js.map} +1 -1
- package/dist/i18n.es.mjs +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.mjs +274 -240
- package/dist/media/index.d.ts +10 -3
- package/dist/media/index.d.ts.map +1 -1
- package/dist/media/observers.d.ts +99 -0
- package/dist/media/observers.d.ts.map +1 -0
- package/dist/media/types.d.ts +125 -0
- package/dist/media/types.d.ts.map +1 -1
- package/dist/media-dAKIGPk3.js +514 -0
- package/dist/media-dAKIGPk3.js.map +1 -0
- package/dist/media.es.mjs +12 -9
- package/dist/{motion-BJsAuULb.js → motion-BBMso9Ir.js} +1 -1
- package/dist/{motion-BJsAuULb.js.map → motion-BBMso9Ir.js.map} +1 -1
- package/dist/motion.es.mjs +1 -1
- package/dist/mount-C8O2vXkQ.js +450 -0
- package/dist/mount-C8O2vXkQ.js.map +1 -0
- package/dist/{platform-Dw2gE3zI.js → platform-BPHIXbw8.js} +17 -16
- package/dist/{platform-Dw2gE3zI.js.map → platform-BPHIXbw8.js.map} +1 -1
- package/dist/platform.es.mjs +1 -1
- package/dist/{plugin-C2WuC8SF.js → plugin-DjTqWg-P.js} +2 -2
- package/dist/{plugin-C2WuC8SF.js.map → plugin-DjTqWg-P.js.map} +1 -1
- package/dist/plugin.es.mjs +1 -1
- package/dist/reactive/index.d.ts +2 -2
- package/dist/reactive/index.d.ts.map +1 -1
- package/dist/reactive/signal.d.ts +2 -1
- package/dist/reactive/signal.d.ts.map +1 -1
- package/dist/reactive/watch.d.ts +49 -0
- package/dist/reactive/watch.d.ts.map +1 -1
- package/dist/reactive/websocket.d.ts +6 -3
- package/dist/reactive/websocket.d.ts.map +1 -1
- package/dist/reactive-BAd2hfl8.js +1171 -0
- package/dist/reactive-BAd2hfl8.js.map +1 -0
- package/dist/reactive.es.mjs +41 -37
- package/dist/readonly-C0ZwS1Tf.js +35 -0
- package/dist/readonly-C0ZwS1Tf.js.map +1 -0
- package/dist/{registry-B08iilIh.js → registry-Cr6VH8CR.js} +1 -1
- package/dist/{registry-B08iilIh.js.map → registry-Cr6VH8CR.js.map} +1 -1
- package/dist/{router-CQikC9Ed.js → router-CCepRMpC.js} +29 -28
- package/dist/{router-CQikC9Ed.js.map → router-CCepRMpC.js.map} +1 -1
- package/dist/router.es.mjs +1 -1
- package/dist/{ssr-_dAcGdzu.js → ssr-D-1IPcfw.js} +4 -4
- package/dist/{ssr-_dAcGdzu.js.map → ssr-D-1IPcfw.js.map} +1 -1
- package/dist/ssr.es.mjs +1 -1
- package/dist/{store-Cb3gPRve.js → store-CjmEeX9-.js} +6 -6
- package/dist/{store-Cb3gPRve.js.map → store-CjmEeX9-.js.map} +1 -1
- package/dist/store.es.mjs +2 -2
- package/dist/{testing-C5Sjfsna.js → testing-TdfaL7VE.js} +8 -8
- package/dist/{testing-C5Sjfsna.js.map → testing-TdfaL7VE.js.map} +1 -1
- package/dist/testing.es.mjs +1 -1
- package/dist/{untrack-D0fnO5k2.js → untrack-bjWDNdyE.js} +11 -10
- package/dist/{untrack-D0fnO5k2.js.map → untrack-bjWDNdyE.js.map} +1 -1
- package/dist/view/directives/aria.d.ts +7 -0
- package/dist/view/directives/aria.d.ts.map +1 -0
- package/dist/view/directives/error.d.ts +7 -0
- package/dist/view/directives/error.d.ts.map +1 -0
- package/dist/view/directives/index.d.ts +2 -0
- package/dist/view/directives/index.d.ts.map +1 -1
- package/dist/view/mount.d.ts.map +1 -1
- package/dist/view/process.d.ts +2 -0
- package/dist/view/process.d.ts.map +1 -1
- package/dist/view.es.mjs +12 -11
- package/package.json +18 -14
- package/src/concurrency/errors.ts +57 -0
- package/src/concurrency/high-level.ts +387 -0
- package/src/concurrency/index.ts +63 -0
- package/src/concurrency/internal.ts +100 -0
- package/src/concurrency/pipeline.ts +133 -0
- package/src/concurrency/pool.ts +450 -0
- package/src/concurrency/reactive.ts +339 -0
- package/src/concurrency/rpc.ts +380 -0
- package/src/concurrency/support.ts +44 -0
- package/src/concurrency/task.ts +318 -0
- package/src/concurrency/types.ts +431 -0
- package/src/full.ts +77 -0
- package/src/index.ts +3 -0
- package/src/media/index.ts +20 -2
- package/src/media/observers.ts +418 -0
- package/src/media/types.ts +136 -0
- package/src/reactive/index.ts +3 -0
- package/src/reactive/signal.ts +2 -1
- package/src/reactive/watch.ts +138 -0
- package/src/reactive/websocket.ts +31 -8
- package/src/view/directives/aria.ts +72 -0
- package/src/view/directives/error.ts +56 -0
- package/src/view/directives/index.ts +2 -0
- package/src/view/mount.ts +4 -0
- package/src/view/process.ts +6 -0
- package/dist/core-DdtZHzsS.js +0 -168
- package/dist/core-DdtZHzsS.js.map +0 -1
- package/dist/media-i-fB5WxI.js +0 -340
- package/dist/media-i-fB5WxI.js.map +0 -1
- package/dist/mount-B4Y8bk8Z.js +0 -403
- package/dist/mount-B4Y8bk8Z.js.map +0 -1
- package/dist/reactive-DwkhUJfP.js +0 -1148
- package/dist/reactive-DwkhUJfP.js.map +0 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime support checks for the concurrency module.
|
|
3
|
+
*
|
|
4
|
+
* @module bquery/concurrency
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { ConcurrencySupport } from './types';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Returns a feature snapshot for zero-build inline worker execution.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* if (!isConcurrencySupported()) {
|
|
15
|
+
* console.warn('Worker tasks are unavailable in this environment.');
|
|
16
|
+
* }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export function getConcurrencySupport(): ConcurrencySupport {
|
|
20
|
+
const worker = typeof globalThis.Worker === 'function';
|
|
21
|
+
const blob = typeof globalThis.Blob === 'function';
|
|
22
|
+
const hasUrl = typeof globalThis.URL !== 'undefined' && globalThis.URL !== null;
|
|
23
|
+
const objectUrl =
|
|
24
|
+
hasUrl &&
|
|
25
|
+
typeof globalThis.URL.createObjectURL === 'function' &&
|
|
26
|
+
typeof globalThis.URL.revokeObjectURL === 'function';
|
|
27
|
+
const abortController = typeof globalThis.AbortController === 'function';
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
worker,
|
|
31
|
+
blob,
|
|
32
|
+
objectUrl,
|
|
33
|
+
abortController,
|
|
34
|
+
supported: worker && blob && objectUrl,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Returns `true` when bQuery can create inline worker tasks in the current
|
|
40
|
+
* environment.
|
|
41
|
+
*/
|
|
42
|
+
export function isConcurrencySupported(): boolean {
|
|
43
|
+
return getConcurrencySupport().supported;
|
|
44
|
+
}
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zero-build worker task helpers.
|
|
3
|
+
*
|
|
4
|
+
* @module bquery/concurrency
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
TaskWorkerAbortError,
|
|
9
|
+
TaskWorkerError,
|
|
10
|
+
TaskWorkerSerializationError,
|
|
11
|
+
TaskWorkerTimeoutError,
|
|
12
|
+
TaskWorkerUnsupportedError,
|
|
13
|
+
} from './errors';
|
|
14
|
+
import {
|
|
15
|
+
createWorkerInstance,
|
|
16
|
+
normalizeTimeout,
|
|
17
|
+
restoreWorkerError,
|
|
18
|
+
validateTaskHandler,
|
|
19
|
+
type SerializedWorkerError,
|
|
20
|
+
} from './internal';
|
|
21
|
+
import { isConcurrencySupported } from './support';
|
|
22
|
+
import type {
|
|
23
|
+
CreateTaskWorkerOptions,
|
|
24
|
+
RunTaskOptions,
|
|
25
|
+
TaskRunOptions,
|
|
26
|
+
TaskWorker,
|
|
27
|
+
TaskWorkerState,
|
|
28
|
+
WorkerTaskHandler,
|
|
29
|
+
} from './types';
|
|
30
|
+
|
|
31
|
+
interface WorkerSuccessMessage<TResult> {
|
|
32
|
+
id: number;
|
|
33
|
+
result: TResult;
|
|
34
|
+
type: 'bq:result';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface WorkerErrorMessage {
|
|
38
|
+
error: SerializedWorkerError;
|
|
39
|
+
id: number;
|
|
40
|
+
type: 'bq:error';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
type WorkerResponse<TResult> = WorkerSuccessMessage<TResult> | WorkerErrorMessage;
|
|
44
|
+
|
|
45
|
+
interface PendingRun<TResult> {
|
|
46
|
+
abortHandler?: () => void;
|
|
47
|
+
id: number;
|
|
48
|
+
reject: (reason?: unknown) => void;
|
|
49
|
+
resolve: (value: TResult | PromiseLike<TResult>) => void;
|
|
50
|
+
timeoutId?: ReturnType<typeof setTimeout>;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const WORKER_RUN_MESSAGE = 'bq:run';
|
|
54
|
+
|
|
55
|
+
const createWorkerScript = (handlerSource: string): string => {
|
|
56
|
+
return `'use strict';
|
|
57
|
+
const serializeError = (error) => {
|
|
58
|
+
if (error && typeof error === 'object') {
|
|
59
|
+
return {
|
|
60
|
+
code: typeof error.code === 'string' ? error.code : undefined,
|
|
61
|
+
message: typeof error.message === 'string' ? error.message : 'Worker task failed.',
|
|
62
|
+
name: typeof error.name === 'string' ? error.name : 'Error',
|
|
63
|
+
stack: typeof error.stack === 'string' ? error.stack : undefined,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
message: typeof error === 'string' ? error : 'Worker task failed.',
|
|
69
|
+
name: 'Error',
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const handler = (${handlerSource});
|
|
74
|
+
|
|
75
|
+
if (typeof handler !== 'function') {
|
|
76
|
+
throw new TypeError('The worker task handler must evaluate to a function.');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
self.onmessage = async (event) => {
|
|
80
|
+
const message = event.data;
|
|
81
|
+
if (!message || message.type !== '${WORKER_RUN_MESSAGE}') {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
const result = await handler(message.payload);
|
|
87
|
+
self.postMessage({ id: message.id, result, type: 'bq:result' });
|
|
88
|
+
} catch (error) {
|
|
89
|
+
self.postMessage({ error: serializeError(error), id: message.id, type: 'bq:error' });
|
|
90
|
+
}
|
|
91
|
+
};`;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Creates a reusable worker task handle around a standalone function.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```ts
|
|
99
|
+
* import { createTaskWorker } from '@bquery/bquery/concurrency';
|
|
100
|
+
*
|
|
101
|
+
* const worker = createTaskWorker((value: number) => value * value, { name: 'square-worker' });
|
|
102
|
+
* const result = await worker.run(12);
|
|
103
|
+
* worker.terminate();
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
export function createTaskWorker<TInput = void, TResult = unknown>(
|
|
107
|
+
handler: WorkerTaskHandler<TInput, TResult>,
|
|
108
|
+
options: CreateTaskWorkerOptions = {}
|
|
109
|
+
): TaskWorker<TInput, TResult> {
|
|
110
|
+
if (!isConcurrencySupported()) {
|
|
111
|
+
throw new TaskWorkerUnsupportedError();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const handlerSource = validateTaskHandler(handler);
|
|
115
|
+
const scriptSource = createWorkerScript(handlerSource);
|
|
116
|
+
const defaultTimeout = normalizeTimeout(options.timeout);
|
|
117
|
+
let disposed = false;
|
|
118
|
+
let worker: Worker | null = null;
|
|
119
|
+
let pending: PendingRun<TResult> | null = null;
|
|
120
|
+
let nextRunId = 0;
|
|
121
|
+
|
|
122
|
+
const cleanupPending = (): void => {
|
|
123
|
+
if (!pending) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (pending.timeoutId !== undefined) {
|
|
128
|
+
clearTimeout(pending.timeoutId);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (pending.abortHandler) {
|
|
132
|
+
pendingAbortSignal?.removeEventListener('abort', pending.abortHandler);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
pending = null;
|
|
136
|
+
pendingAbortSignal = undefined;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
let pendingAbortSignal: AbortSignal | undefined;
|
|
140
|
+
|
|
141
|
+
const detachWorker = (): void => {
|
|
142
|
+
if (!worker) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
worker.onmessage = null;
|
|
147
|
+
worker.onerror = null;
|
|
148
|
+
worker.terminate();
|
|
149
|
+
worker = null;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const rejectPending = (error: Error): void => {
|
|
153
|
+
if (!pending) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const current = pending;
|
|
158
|
+
cleanupPending();
|
|
159
|
+
current.reject(error);
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const ensureWorker = (): Worker => {
|
|
163
|
+
if (disposed) {
|
|
164
|
+
throw new TaskWorkerError('The task worker has already been terminated.', 'TERMINATED');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (worker) {
|
|
168
|
+
return worker;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const instance = createWorkerInstance(scriptSource, options.name);
|
|
172
|
+
instance.onmessage = (event: MessageEvent<WorkerResponse<TResult>>) => {
|
|
173
|
+
const current = pending;
|
|
174
|
+
if (!current) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const message = event.data;
|
|
179
|
+
if (!message || message.id !== current.id) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
cleanupPending();
|
|
184
|
+
|
|
185
|
+
if (message.type === 'bq:error') {
|
|
186
|
+
current.reject(restoreWorkerError(message.error));
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
current.resolve(message.result);
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
instance.onerror = (event: ErrorEvent) => {
|
|
194
|
+
const error = new TaskWorkerError(event.message || 'Worker execution failed.', 'WORKER');
|
|
195
|
+
detachWorker();
|
|
196
|
+
rejectPending(error);
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
worker = instance;
|
|
200
|
+
return instance;
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
const resetAfterInterruptedRun = (error: Error): void => {
|
|
204
|
+
detachWorker();
|
|
205
|
+
rejectPending(error);
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
get busy(): boolean {
|
|
210
|
+
return pending !== null;
|
|
211
|
+
},
|
|
212
|
+
get state(): TaskWorkerState {
|
|
213
|
+
if (disposed) {
|
|
214
|
+
return 'terminated';
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return pending ? 'running' : 'idle';
|
|
218
|
+
},
|
|
219
|
+
run(input: TInput, runOptions: TaskRunOptions = {}): Promise<TResult> {
|
|
220
|
+
if (disposed) {
|
|
221
|
+
return Promise.reject(
|
|
222
|
+
new TaskWorkerError('The task worker has already been terminated.', 'TERMINATED')
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (pending) {
|
|
227
|
+
return Promise.reject(
|
|
228
|
+
new TaskWorkerError(
|
|
229
|
+
'This task worker is already running a task. Create another worker or wait for the current task to finish.',
|
|
230
|
+
'BUSY'
|
|
231
|
+
)
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (runOptions.signal?.aborted) {
|
|
236
|
+
return Promise.reject(new TaskWorkerAbortError());
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const activeWorker = ensureWorker();
|
|
240
|
+
const timeout = normalizeTimeout(runOptions.timeout) ?? defaultTimeout;
|
|
241
|
+
const runId = nextRunId++;
|
|
242
|
+
|
|
243
|
+
return new Promise<TResult>((resolve, reject) => {
|
|
244
|
+
const current: PendingRun<TResult> = {
|
|
245
|
+
id: runId,
|
|
246
|
+
reject,
|
|
247
|
+
resolve,
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
if (runOptions.signal) {
|
|
251
|
+
current.abortHandler = () => {
|
|
252
|
+
resetAfterInterruptedRun(new TaskWorkerAbortError());
|
|
253
|
+
};
|
|
254
|
+
pendingAbortSignal = runOptions.signal;
|
|
255
|
+
runOptions.signal.addEventListener('abort', current.abortHandler, { once: true });
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (timeout !== undefined) {
|
|
259
|
+
current.timeoutId = setTimeout(() => {
|
|
260
|
+
resetAfterInterruptedRun(
|
|
261
|
+
new TaskWorkerTimeoutError(`Worker task exceeded the timeout of ${timeout}ms.`)
|
|
262
|
+
);
|
|
263
|
+
}, timeout);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
pending = current;
|
|
267
|
+
|
|
268
|
+
try {
|
|
269
|
+
activeWorker.postMessage(
|
|
270
|
+
{ id: runId, payload: input, type: WORKER_RUN_MESSAGE },
|
|
271
|
+
runOptions.transfer ?? []
|
|
272
|
+
);
|
|
273
|
+
} catch (error) {
|
|
274
|
+
detachWorker();
|
|
275
|
+
rejectPending(
|
|
276
|
+
new TaskWorkerSerializationError(
|
|
277
|
+
'Failed to serialize the task input or transfer list for worker execution.',
|
|
278
|
+
error
|
|
279
|
+
)
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
},
|
|
284
|
+
terminate(): void {
|
|
285
|
+
if (disposed) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
disposed = true;
|
|
290
|
+
detachWorker();
|
|
291
|
+
rejectPending(new TaskWorkerError('The task worker was terminated.', 'TERMINATED'));
|
|
292
|
+
},
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Executes a single task in a fresh worker and tears it down afterwards.
|
|
298
|
+
*
|
|
299
|
+
* @example
|
|
300
|
+
* ```ts
|
|
301
|
+
* import { runTask } from '@bquery/bquery/concurrency';
|
|
302
|
+
*
|
|
303
|
+
* const result = await runTask((value: number) => value * 2, 21);
|
|
304
|
+
* ```
|
|
305
|
+
*/
|
|
306
|
+
export async function runTask<TInput = void, TResult = unknown>(
|
|
307
|
+
handler: WorkerTaskHandler<TInput, TResult>,
|
|
308
|
+
input: TInput,
|
|
309
|
+
options: RunTaskOptions = {}
|
|
310
|
+
): Promise<TResult> {
|
|
311
|
+
const worker = createTaskWorker(handler, options);
|
|
312
|
+
|
|
313
|
+
try {
|
|
314
|
+
return await worker.run(input, options);
|
|
315
|
+
} finally {
|
|
316
|
+
worker.terminate();
|
|
317
|
+
}
|
|
318
|
+
}
|