Skip to content

lib: add support for JSTransferable as a mixin#38383

Closed
jasnell wants to merge 1 commit intonodejs:masterfrom
jasnell:jstransferable_mixin
Closed

lib: add support for JSTransferable as a mixin#38383
jasnell wants to merge 1 commit intonodejs:masterfrom
jasnell:jstransferable_mixin

Conversation

@jasnell
Copy link
Copy Markdown
Member

@jasnell jasnell commented Apr 24, 2021

@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

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author ready PRs that have at least one approval, no pending requests for changes, and a CI started. build Issues and PRs related to build files or the CI. test Issues and PRs related to the tests. worker Issues and PRs related to Worker support.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants