API reference › @evolu/common › Worker › MessageChannel
Defined in: packages/common/src/Worker.ts:226
Typed, disposable MessageChannel.
Creates two entangled ports: keep one and transfer the other (e.g., to a
SharedWorker via postMessage with transfer). Messages sent to one port
are received by the other.
Messages are queued until onMessage is assigned, enabling safe async
initialization. The sender can post messages immediately while the receiver
performs async setup — no manual buffering required.
For one-way communication, omit Output (defaults to never).
Transfer a channel port to a SharedWorker and use the retained port immediately:
import {
assertEqual,
createMessageChannel,
createMessagePort,
createSharedWorker,
type NativeMessagePort,
} from "@evolu/common";
interface Query {
readonly text: string;
}
interface QueryResult {
readonly rows: ReadonlyArray<string>;
}
interface ConnectToEvolu {
readonly port: NativeMessagePort<QueryResult, Query>;
}
const response = Promise.withResolvers<QueryResult>();
using sharedWorker = createSharedWorker<ConnectToEvolu>((self) => {
self.onConnect = (controlPort) => {
controlPort.onMessage = ({ port }) => {
const workerQueries = createMessagePort<QueryResult, Query>(port);
workerQueries.onMessage = (query) => {
workerQueries.postMessage({ rows: [query.text] });
workerQueries[Symbol.dispose]();
};
};
};
});
using queryChannel = createMessageChannel<Query, QueryResult>();
queryChannel.port1.onMessage = response.resolve;
// The main thread retains port1 and transfers the worker-facing port2.
sharedWorker.port.postMessage({ port: queryChannel.port2.native }, [
queryChannel.port2.native,
]);
queryChannel.port1.postMessage({ text: "all todos" });
assertEqual(await response.promise, { rows: ["all todos"] });
On the worker side, attach the handler after asynchronous initialization; messages sent earlier remain queued:
import {
assertEqual,
createMessageChannel,
createMessagePort,
} from "@evolu/common";
interface Query {
readonly text: string;
}
using channel = createMessageChannel<Query>();
using workerPort = createMessagePort<never, Query>(channel.port2.native);
const received: Array<Query> = [];
const allReceived = Promise.withResolvers<void>();
// The main thread can send several messages while the worker initializes.
channel.port1.postMessage({ text: "all todos" });
channel.port1.postMessage({ text: "completed todos" });
await Promise.resolve();
workerPort.onMessage = (query) => {
received.push(query);
if (received.length === 2) allReceived.resolve();
};
await allReceived.promise;
assertEqual(received, [{ text: "all todos" }, { text: "completed todos" }]);
See
https://developer.mozilla.org/en-US/docs/Web/API/MessageChannel
Extends
Extended by
Methods
[dispose]()
dispose: void;
Defined in: node_modules/@typescript/old/lib/lib.esnext.disposable.d.ts:34
Inherited from
Disposable.[dispose]
Properties
port1
readonly port1: MessagePort<Input, Output>;
Defined in: packages/common/src/Worker.ts:228
The first port of the channel.
port2
readonly port2: MessagePort<Output, Input>;
Defined in: packages/common/src/Worker.ts:231
The second port of the channel.