Tomáš Zato
Tomáš Zato

Reputation: 53338

What interface do I need to implement to allow object to be passed through WebWorker's postMessage?

WebWorkers API in javascript allows you to pass objects between worker's thread and main thread using worker.postMessage in browser and postMessage in Worker.

I've been playing around, and not only that the postMessage passed arrays and objects but even RegExp instances, so I assume there's some interface these objects implement. For example for string conversion, you implement .toString method:

"" + {toString: function() {return "Hello world!"}}; //prints `Hello world!`

Similarly, you can implement toJSON method:

JSON.stringify({toJSON: alert});
//Throws `TypeError: 'alert' called on an object that does not implement interface Window.`
//  - demonstrating that toJSON is being called

My question is, what should I implement for postMessage to get my Player class pass through communication channel:

function Player(name) {
  this.name = name;
}
Player.prototype = Object.create(EventEmitter2.prototype);

I intentionally added the inheritance part here - I need for the object to remain instance of something, not just data holder. Just as with RegExp, I need it to be reconstructed through method or methods that I define - which must fail if required context (type definitions, such as EventEmitter2) are not defined in new scope.

Upvotes: 3

Views: 1218

Answers (1)

Zirak
Zirak

Reputation: 39848

Alas, you can't. You can't specify your own serialiser/deserialiser (or marshaller/unmarshaller). You can retain object structures though, which in most cases is good enough, but information like constructors and functions won't pass through.

Here's how I know this:

The part of the specification in charge of a web worker's postMessage (which is the same as a window's postMessage, by the way) can be found here: https://html.spec.whatwg.org/multipage/comms.html#dom-messageport-postmessage

It's a lot of uninteresting technical stuff, but the important part is this:

Let message clone be the result of obtaining a structured clone of the message argument, [...]

The structured clone algorithm is here: https://html.spec.whatwg.org/multipage/infrastructure.html#structured-clone

As you can see, things look pretty grim. It checks for built-in objects and values (like Number or Blob), and construct them accordingly. You can pass arbitrary objects, but only their structure will remain.


So, what can you do?

  1. Accept it. Only data goes through, like JSON only more limited. That's not so bad actually, and encourages separation of transport layer and implementation.
  2. Implement a marshaller/unmarshaller of your own, wrap postMessage and the likes. That's not so terribly difficult actually, and can be a nice exercise.
  3. Weep bitter tears. I like this option, it helps deal with day-to-day life.

Upvotes: 2

Related Questions