I came across the following code looking at the source of ws
(a popular WebSocket implementation for Node.js):
const FastBuffer = Buffer[Symbol.species];
So, how do they use this FastBuffer
? Well, no custom implementations or any added code, they just use it to make Buffer
instances from other buffers:
this._buffers[0] = new FastBuffer(
buf.buffer,
buf.byteOffset + n,
buf.length - n
);
return new FastBuffer(buf.buffer, buf.byteOffset, n);
It is well known that the Buffer
constructors are deprecated, but aside from that I couldn't even find a constructor definition that receives an offset
and a length
like the one that ws
seems to be using.
What is this code doing under the hood to access that constructor? How does this add performance? Is this documented somewhere?
What is this code doing under the hood to access that constructor?
Let's start with the purpose of the Symbol.species
/@@species
pattern: It allows subclasses to define what constructor should be used to create new instances. You would often use it on an instance you wanted to copy (someObject.constructor[Symbol.species]
), but you can use it on the class directly.
Looking at what it returns, it's the FastBuffer
class that Node.js uses internally (those line numbers will rot), which is a class inheriting directly from Uint8Array
(not from Buffer
).
The fact that Buffer
supports @@species
is not documented, so the code you're quoting would appear to be hooking into and relying on Node.js internals.
How does this add performance?
I can't point to something specific, but presumably the Node.js implementers called it FastBuffer
for a reason. :-) Probably by not being a full Buffer
it can have optimizations that Buffer
can't have.
Is this documented somewhere?
It's hard to prove a negative, but the @@species
on Buffer
isn't, nor does a search for FastBuffer
on the Node.js API docs turn anything up.
It is well known that the
Buffer
constructors are deprecated, but aside from that I couldn't even find a constructor definition that receives anoffset
and alength
like the one thatws
seems to be using.
Since what we're getting back isn't necessarily a Buffer
, it doesn't really matter, but Buffer
does have that constructor. But more importantly, the (internal?) FastBuffer
class supports that signature, as does its parent class Uint8Array
.