lib: add support for JSTransferable as a mixin
@addaleax ... Very interested in what you think on this... the use case is that I want to define internal classes that are both transferable and extend NodeEventTarget
but without forcing all NodeEventTarget
instances to be cloneable or incur the cost of extending JSTransferable
. Because we can't use multiple inheritance this uses JSTransferable
as a kind of mixin.
This is not a public facing API. It is inteded for internal use only for now.
Adds a new makeTransferable()
utility that can construct a
JSTransferable
object that does not directly extend the
JSTransferable
JavaScript class.
Because JavaScript does not support multiple inheritance, it is
not possible (without help) to implement a class that extends
both JSTransferable
and, for instance, EventTarget
without
incurring a significant additional complexity and performance
cost by making all EventTarget
instances extend JSTransferable
...
That is, we don't want:
class EventTarget extends JSTransferable { ... }
The makeTransferable()
allows us to create objects that are
backed internally by JSTransferable
without having to actually
extend it by leveraging the magic of Reflect.construct()
.
const {
JSTransferable,
kClone,
kDeserialize,
makeTransferable,
} = require('internal/worker/js_transferable');
class E {
constructor(b) {
this.b = b;
}
}
class F extends E {
constructor(b) {
super(b);
return makeTransferable(this);
}
[kClone]() { /** ... **/ }
[kDeserialize]() { /** ... **/ }
}
const f = new F();
f instanceof F; // true
f instanceof E; // true
f instanceof JSTransferable; // false
const mc = new MessageChannel();
mc.port1.onmessage = ({ data }) => {
data instanceof F; // true
data instanceof E; // true
data instanceof JSTransferable; // false
};
mc.port2.postMessage(f); // works!
The additional internal/test/transfer.js
file is required for the
test because successfully deserializing transferable classes requires
that they be located in lib/internal
for now.
Signed-off-by: James M Snell jasnell@gmail.com