Transferable objects
Move large buffers between threads without copying them, in both directions.
Copy or transfer
Values sent to a worker are copied by default. For a large ArrayBuffer that means allocating the same memory
twice. A transfer moves ownership instead: the receiving thread gets the memory, and the sender is left with
an empty buffer.
ArrayBuffer, MessagePort, ImageBitmap, OffscreenCanvas and streams are
transferable.
From the main thread to the worker
The second argument of every method is the transfer list.
main.ts
import { createWorker } from 'easy-web-worker/createWorker';
import workerUrl from './images.worker?worker&url';
import type { ImagesWorker } from './images.worker';
const images = createWorker<ImagesWorker>(workerUrl, {
workerOptions: { type: 'module' },
});
export async function invert(file: File) {
const buffer = await file.arrayBuffer();
// the second argument is the transfer list
const inverted = await images.invert(buffer, [buffer]);
console.log(buffer.byteLength); // 0: the memory moved to the worker
console.log(inverted.byteLength); // the full size, moved back
return inverted;
}From the worker back to the main thread
A returned value is always copied. To transfer a result, complete the call yourself and pass the transfer list
to message.resolve.
images.worker.ts
import { defineWorker } from 'easy-web-worker/defineWorker';
const worker = defineWorker(({ onMessage }) => ({
// a returned value is copied
histogram: (pixels: ArrayBuffer) => {
const counts = new Array<number>(256).fill(0);
new Uint8Array(pixels).forEach((value) => {
counts[value] += 1;
});
return counts;
},
// to transfer the result, complete the call yourself
invert: onMessage<ArrayBuffer, ArrayBuffer>().handle((message) => {
const bytes = new Uint8Array(message.payload);
for (let index = 0; index < bytes.length; index++) {
bytes[index] = 255 - bytes[index];
}
message.resolve(bytes.buffer, [bytes.buffer]);
}),
}));
export type ImagesWorker = typeof worker;reject, cancel and reportProgress accept a transfer list too.
Try it
The transferable buffers example sends the same buffer as a copy and as a transfer, and measures both.