COMMUNITY

Best way of dealing with haxe enums and js.Worker.postMessage serialization

JS doesn’t natively allow haxe enums, maps etc be passed to/from webworkers, due to the restrictions in the structured cloning algorithm. (The structured clone algorithm - Web APIs | MDN)

So, haxe objects containing enums have to be “serialized” to simple javascript objects containing only object literals (no functions etc…) Elnabo’s json2object json2object (3.9.0) (based on Nadako’s GitHub - nadako/hxjsonast: Parse JSON into position-aware AST with Haxe!) is my goto solution for serializing haxe objects to plain json and back, but this solution (of course) results in a json string, not an object.

Someone know of a lightweight and quick object translator around that can convert a haxe object to/from a simple js object that can be handled by the structured clone algorithm?

Other ideas?

// Jonas

Why do you want an object, if it is going to be serialized at the end anyway?

Well, inspired by this talk: The main thread is overworked & underpaid (Chrome Dev Summit 2019) - YouTube, I just thinking about ways of moving non-UI stuff like state handling, data-fetching etc. away from the main js thread - preferrably without giving up using Haxe enums, maps etc. on either side.

Surma’s Comlink GitHub - GoogleChromeLabs/comlink: Comlink makes WebWorkers enjoyable. is a very neat way of communicating between main thread and WebWorkers, and having something like that in Haxe, with full Haxe type-system support, would just be great…! :slight_smile:

Sorry if I misunderstood your question, Kevin! I could postMessage the Haxe objects as strings, you mean…? Yes, that should work, of course. Just thought that I would shave of some ms’s by not having to convert them to/from strings… I guess that I have some profiling work to do…

The current representation of enums is chosen to actually work with JSON (it is a plain object that refers to its own enum indirectly via name) and as a result it also fits with the structured clone algorithm. The two remaining problems then are:

  1. Maps. For this I would advise making your own implementation of Map on top of js.lib.Map. You can call Context.defineType in a --macro to take precedence over the stdlib version.
  2. Your own classes. There’s not much you can do about this.

If you want to squeeze out maximum performance, then I would suggest not using your own classes, as that will avoid any translation at all (you can use macros to statically ensure the data sent is clonable). If you do, it really doesn’t matter whether you build a string or another object graph.

Right now, your communication is this:

ActualData ---(serialize)---> String ---(unserialize)---> ActualData

And instead you’re going for this:

ActualData ---(translate)---> CloneableData ---(clone)---> ClonedData ---(untranslate)---> ActualData

It’s not clear that that’s going to be faster (even if you assume that the structured cloning has no cost at all).