Methods and the message
The three ways to write a worker method, what the message of a call offers, and the controls behind the methods.
Three ways to write a method
import { defineWorker } from 'easy-web-worker/defineWorker';
const worker = defineWorker(({ onMessage }) => ({
// 1. a plain function: the returned value resolves the call
double: (value: number) => value * 2,
// 2. onMessage: the same, with the message and the event typed for you
count: onMessage(async (to: number, message, event) => {
message.reportProgress(50, { messageId: event.data.messageId });
return to;
}),
// 3. onMessage().handle: only the message, and you complete it
wait: onMessage<number, string>().handle((message) => {
const timeoutId = setTimeout(() => message.resolve('done'), message.payload);
message.onCancel(() => clearTimeout(timeoutId));
}),
}));
export type ThreeWaysWorker = typeof worker;| Style | Completes the call | Types |
|---|---|---|
| Plain function | With the returned value | Inferred |
onMessage((payload, message, event) => ...) | With the returned value | Inferred, message typed |
onMessage<P, R>().handle((message) => ...) | You do | Explicit, message.resolve typed |
All three are called the same way from the main thread.
- Use a plain function when the method only needs its payload.
- Use
onMessagewhen it also reports progress or reacts to a cancellation. The wrapper exists to give the second parameter its type; a plain function receives the same arguments. - Use
onMessage().handlefor timers, streams and event-based APIs, or to transfer a result.
A method with no payload
To reach the message without a payload, declare the first parameter as null.
import { defineWorker } from 'easy-web-worker/defineWorker';
const worker = defineWorker(({ onMessage }) => ({
// the payload is declared as null to reach the message
status: onMessage((_payload: null, message) => {
message.reportProgress(50);
return 'ready';
}),
}));
export type StatusWorker = typeof worker;The message
Available as second parameter of a method, in .handle(...), and in the message API.
| Member | Purpose |
|---|---|
payload | Value sent from the main thread |
resolve(result?, transfer?) | Resolves the call |
reject(reason?, transfer?) | Rejects the call |
cancel(reason?, transfer?) | Cancels the call from inside the worker |
reportProgress(percentage, payload?, transfer?) | Reports progress and keeps the call pending |
onCancel, onResolve, onReject, onProgress | Subscribe to each outcome; return unsubscribe |
onFinalize | Runs once the call ends, whatever the outcome |
isPending(), getStatus() | Current state of the call |
onFinalize is the place to release what a call opened:
import { defineWorker } from 'easy-web-worker/defineWorker';
const worker = defineWorker(({ onMessage }) => ({
watch: onMessage<string, void>().handle((message) => {
const source = new EventSource(message.payload);
source.onmessage = (event) => message.reportProgress(0, event.data);
source.onerror = () => message.reject(new Error('Connection lost'));
// runs once, whether the call was resolved, rejected or canceled
message.onFinalize(() => source.close());
}),
}));
export type WatchWorker = typeof worker;The event
The third parameter of a method is the original MessageEvent received by the worker. It is rarely needed; it
is there for code that inspects the raw message.
The controls behind the methods
The object returned by defineWorker describes the methods. unwrap reaches the worker behind it: onMessage
for messages sent without a method, importScripts and close.
import { defineWorker, unwrap } from 'easy-web-worker/defineWorker';
const worker = defineWorker(() => ({
ping: () => 'pong',
}));
// the worker-side controls behind the methods
unwrap(worker).importScripts('https://example.com/library.js');
// handles the messages sent without a method: send, override, overrideAfterCurrent
unwrap(worker).onMessage((message) => {
message.resolve();
});
export type PingWorker = typeof worker;The same helper works on the main thread, where it returns the EasyWebWorker instance. See the
API reference.