Transferable objects are objects that own resources that can be transferred from one context to another, ensuring that the resources are only available in one context at a time. Following a transfer, the original object is no longer usable; it no longer points to the transferred resource, and any attempt to read or write the object will throw an exception.
Transferable objects are commonly used to share resources that can only be safely exposed to a single JavaScript thread at a time. For example, an ArrayBuffer
is a transferable object that owns a block of memory. When such a buffer is transferred between threads, the associated memory resource is detached from the original buffer and attached to the buffer object created in the new thread. The buffer object in the original thread is no longer usable because it no longer owns a memory resource.
Transferring may also be used when creating deep copies of objects with structuredClone()
. Following the cloning operation, the transferred resources are moved rather than copied to the cloned object.
The mechanism used to transfer an object's resources depends on the object. For example, when an ArrayBuffer
is transferred between threads, the memory resource that it points to is literally moved between contexts in a fast and efficient zero-copy operation. Other objects may be transferred by copying the associated resource and then deleting it from the old context.
Not all objects are transferable. A list of transferable objects is provided below.
The code below demonstrates how transferring works when sending a message from a main thread to a web worker thread. The Uint8Array
is copied (duplicated) in the worker while its buffer is transferred. After transfer any attempt to read or write uInt8Array
from the main thread will throw, but you can still check the byteLength
to confirm it is now zero.
const uInt8Array = new Uint8Array(1024 * 1024 * 8).map((v, i) => i);
console.log(uInt8Array.byteLength);
worker.postMessage(uInt8Array, [uInt8Array.buffer]);
console.log(uInt8Array.byteLength);
Note: Typed arrays like Int32Array
and Uint8Array
, are serializable, but not transferable. However their underlying buffer is an ArrayBuffer
, which is a transferable object. We could have sent uInt8Array.buffer
in the data parameter, but not uInt8Array
in the transfer array.
The code below shows a structuredClone()
operation where the underlying buffer is copied from the original object to the clone.
const original = new Uint8Array(1024);
const clone = structuredClone(original);
console.log(original.byteLength);
console.log(clone.byteLength);
original[0] = 1;
console.log(clone[0]);
const transferred = structuredClone(original, { transfer: [original.buffer] });
console.log(transferred.byteLength);
console.log(transferred[0]);
console.log(original.byteLength);
The items that various specifications indicate can be transferred are:
Browser support should be indicated in the respective object's compatibility information by the transferable
subfeature (see RTCDataChannel
for an example). At time of writing, not all transferable objects have been updated with this information.
Note: Transferable objects are marked up in Web IDL files with the attribute [Transferable]
.