12

Since Web-Worker JSON serialize data between threads, something like this doesn't work:

worker.js

function Animal() {}
Animal.prototype.foobar = function() {}

self.onmessage = function(e) {
  self.postMessage({animal: new Animal()})  
}

main.js

let worker = new Worker('worker.js')

worker.onmessage = function(e) {
    console.log(e.data)
}

worker.postMessage('go!')

The outcome would be a simple object with the loss of the foobar prototype method.

Is it possible to transfer the custom object back to the main thread without losing its prototype methods? Like, would this be possible with ArrayBuffer? I'm not familiar with that stuff, so I'm a bit lost.

Martin Broder
  • 221
  • 3
  • 14

2 Answers2

2
  1. Assuming you program both the client and the webservice you can define the Animal function in boths sides
  2. Then you can add to Animal.prototype (in both sides) toJson method to pass the info you need to recreate the object (and may be choose some attribute to define the className)
  3. You define a reviver that use the reverse process
  4. Then when you post you must always JSON.stringify(e)
  5. In the onmessage you JSON.parse(m,reviver)

    function Animal(name, age){
       var private_name = name;
       this.public_age = age;
       this.log = function(){
         console.log('Animal', private_name, this.public_age);
       }
       this.toJson = function(){
         return JSON.stringify({
           __type__:'Animal',  // name of class
           __args__:[this.public_age, private_name] // same args that construct
         });
       }        
    }
    
    Animal.prototype.age = function(){
       return this.public_age;
    }
    
    var a = new Animal('boby', 6);
    
    worker.postMessage(JSON.stringify(a));
    
    function reviver(o){
      if(o.__type__){
        var constructor=reviver.register[o.__type__];
        if(!constructor) throw Error('__type__ not recognized');
        var newObject = {};
        return constructor.apply(newObject, o.__args__);
      }
      return o;
    }
    
    reviver.register={}; // you can register any classes
    
    reviver.register['Animal'] = Animal;
    
    worker.onmessage = function(m){
      var a = JSON.parse(e, reviver);
    }
    
Emilio Platzer
  • 2,327
  • 21
  • 29
  • Thanks for your comment Emilio. While your script is not 100% functional, I get the point. But wouldn't a simple `new Animal(JSON.parse(e.data))` do the same thing? No need for a reviver? Or is your solution somewhat faster? My main goal is to keep most of the work within the worker, without blocking the main thread. – Martin Broder Aug 12 '15 at 02:16
  • Yes, is not 100% functional (I wrote "in the fly"). – Emilio Platzer Aug 12 '15 at 02:18
  • If you know that you always transfer an Animal you don't need all this stuf, you can simply pass then minimum data for recreate it. But if you can pass anything of any type, you can use this aproach. I.e.: `var zoo = new Zoo({jail1: new Lion('pepe',12), jail2: new Tigger('winny', 5)}); worker.postMessage(zoo);` – Emilio Platzer Aug 12 '15 at 02:21
0

There is a simple way without set prototypes, also without convert to string with JSON.stringify, you need to build to function:

  • toObject(instance):obj, instance is and instance class and will be converted to and object
  • toInstanceClass(obj):instance, obj is and object and will return and instance from your class

You need to pass your obj to the worker, in the worker you'll build your instance from your class, make all your operations and return like and obj

In your main thread you'll need to rebuild your instance from your class by the returned obj from worker, that's all.

General Grievance
  • 4,555
  • 31
  • 31
  • 45
elVengador
  • 299
  • 3
  • 10