-
Notifications
You must be signed in to change notification settings - Fork 29.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
lib: add support for JSTransferable as a mixin
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: ```js 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()`. ```js const { JSTransferable, kClone, kDeserialize, kConstructor, makeTransferable, } = require('internal/worker/js_transferable'); class E { constructor(b) { this.b = b; } } class F extends E { [kClone]() { /** ... **/ } [kDeserialize]() { /** ... **/ } static [kConstructor]() { return makeTransferable(F); } } const f = makeTransferable(F, 1); 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 branch information
Showing
4 changed files
with
86 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
'use strict'; | ||
|
||
const { | ||
makeTransferable, | ||
kClone, | ||
kDeserialize, | ||
} = require('internal/worker/js_transferable'); | ||
|
||
process.emitWarning( | ||
'These APIs are for internal testing only. Do not use them.', | ||
'internal/test/transfer'); | ||
|
||
// Used as part of parallel/test-messaging-maketransferable. | ||
// This has to exist within the lib/internal/ path in order | ||
// for deserialization to work. | ||
|
||
class E { | ||
constructor(b) { | ||
this.b = b; | ||
} | ||
} | ||
|
||
class F extends E { | ||
constructor(b) { | ||
super(b); | ||
/* eslint-disable-next-line no-constructor-return */ | ||
return makeTransferable(this); | ||
} | ||
|
||
[kClone]() { | ||
return { | ||
data: { b: this.b }, | ||
deserializeInfo: 'internal/test/transfer:F' | ||
}; | ||
} | ||
|
||
[kDeserialize]({ b }) { | ||
this.b = b; | ||
} | ||
} | ||
|
||
module.exports = { E, F }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// Flags: --expose-internals | ||
'use strict'; | ||
|
||
const common = require('../common'); | ||
|
||
const assert = require('assert'); | ||
const { | ||
JSTransferable, | ||
} = require('internal/worker/js_transferable'); | ||
const { E, F } = require('internal/test/transfer'); | ||
|
||
// Tests that F is transferable even tho it does not directly, | ||
// observably extend the JSTransferable class. | ||
|
||
const mc = new MessageChannel(); | ||
|
||
mc.port1.onmessageerror = common.mustNotCall(); | ||
|
||
mc.port1.onmessage = common.mustCall(({ data }) => { | ||
assert(!(data instanceof JSTransferable)); | ||
assert(data instanceof F); | ||
assert(data instanceof E); | ||
assert.strictEqual(data.b, 1); | ||
mc.port1.close(); | ||
}); | ||
|
||
mc.port2.postMessage(new F(1)); |