Skip to content

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

Merge request reports

Loading