传输 TypedArray 和 Buffer 时的注意事项
所有 TypedArray
和 Buffer
实例都是对底层 ArrayBuffer
的视图。
也就是说,实际存储原始数据的是 ArrayBuffer
,而 TypedArray
和 Buffer
对象提供了查看和操作数据的方式。
在同一个 ArrayBuffer
实例上创建多个视图是可能且常见的。
使用传输列表传输 ArrayBuffer
时必须非常小心,因为这样做会导致共享同一个 ArrayBuffer
的所有 TypedArray
和 Buffer
实例变得不可用。
const ab = new ArrayBuffer(10);
const u1 = new Uint8Array(ab);
const u2 = new Uint16Array(ab);
console.log(u2.length); // 打印 5
port.postMessage(u1, [u1.buffer]);
console.log(u2.length); // 打印 0
对于 Buffer
实例,具体来说,底层 ArrayBuffer
是否可以被传输或克隆完全取决于实例是如何创建的,这通常无法可靠地确定。
ArrayBuffer
可以用 markAsUntransferable()
标记来表示它应该总是被克隆并且永远不会被传输。
根据 Buffer
实例的创建方式,它可能拥有也可能不拥有其底层 ArrayBuffer
。
除非知道 Buffer
实例拥有它,否则不得传输 ArrayBuffer
。
特别是,对于从内部 Buffer
池(使用,例如 Buffer.from()
或 Buffer.alloc()
)创建的 Buffer
,传输它们是不可能的,它们将始终被克隆,这会发送整个 Buffer
池的副本。
此行为可能会带来意想不到的更高内存使用率和可能的安全问题。
有关 Buffer
池化的更多详细信息,请参阅 Buffer.allocUnsafe()
。
使用 Buffer.alloc()
或 Buffer.allocUnsafeSlow()
创建的 Buffer
实例的 ArrayBuffer
始终可以传输,但这样做会使那些 ArrayBuffer
的所有其他现有视图无法使用。
All TypedArray
and Buffer
instances are views over an underlying
ArrayBuffer
. That is, it is the ArrayBuffer
that actually stores
the raw data while the TypedArray
and Buffer
objects provide a
way of viewing and manipulating the data. It is possible and common
for multiple views to be created over the same ArrayBuffer
instance.
Great care must be taken when using a transfer list to transfer an
ArrayBuffer
as doing so will cause all TypedArray
and Buffer
instances that share that same ArrayBuffer
to become unusable.
const ab = new ArrayBuffer(10);
const u1 = new Uint8Array(ab);
const u2 = new Uint16Array(ab);
console.log(u2.length); // prints 5
port.postMessage(u1, [u1.buffer]);
console.log(u2.length); // prints 0
For Buffer
instances, specifically, whether the underlying
ArrayBuffer
can be transferred or cloned depends entirely on how
instances were created, which often cannot be reliably determined.
An ArrayBuffer
can be marked with markAsUntransferable()
to indicate
that it should always be cloned and never transferred.
Depending on how a Buffer
instance was created, it may or may
not own its underlying ArrayBuffer
. An ArrayBuffer
must not
be transferred unless it is known that the Buffer
instance
owns it. In particular, for Buffer
s created from the internal
Buffer
pool (using, for instance Buffer.from()
or Buffer.alloc()
),
transferring them is not possible and they will always be cloned,
which sends a copy of the entire Buffer
pool.
This behavior may come with unintended higher memory
usage and possible security concerns.
See Buffer.allocUnsafe()
for more details on Buffer
pooling.
The ArrayBuffer
s for Buffer
instances created using
Buffer.alloc()
or Buffer.allocUnsafeSlow()
can always be
transferred but doing so will render all other existing views of
those ArrayBuffer
s unusable.