如何通过Web Workers传递自定义类实例?

12

由于 Web Worker 在线程之间序列化 JSON 数据,因此像这样的东西不起作用:

worker.js

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

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

main.js


(Note: This is already in Chinese. It simply states the file name "main.js" within HTML code.)
let worker = new Worker('worker.js')

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

worker.postMessage('go!')

结果将是一个简单的对象,其中丢失了foobar原型方法。

是否可以在不丢失其原型方法的情况下将自定义对象传输回主线程?比如说,使用ArrayBuffer是否可能实现这一点?我对这方面不太熟悉,所以有些迷茫。

2个回答

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。虽然您的脚本不是100%功能完整,但我明白了您的意思。但是,一个简单的new Animal(JSON.parse(e.data))不是也可以实现同样的效果吗?没有必要使用reviver吗?或者您的解决方案更快一些?我的主要目标是在工作线程内完成大部分工作,而不会阻塞主线程。 - Martin Broder
是的,它不是100%功能(我写的时候是“在飞行中”)。 - Emilio Platzer
如果您知道您总是传输一个动物,您不需要所有这些东西,您可以简单地传递重新创建它所需的最小数据。但是,如果您可以传递任何类型的任何内容,则可以使用此方法。例如:var zoo = new Zoo({jail1: new Lion('pepe',12), jail2: new Tigger('winny', 5)}); worker.postMessage(zoo); - Emilio Platzer

1

有一种简单的方法,不需要设置原型,也不需要使用JSON.stringify将其转换为字符串,您需要构建以下两个函数:

  • toObject(instance):objinstance是一个实例类,将被转换为对象
  • toInstanceClass(obj):instanceobj是一个对象,将返回您类的实例

您需要将您的obj传递给worker,在worker中,您将从您的类构建实例,执行所有操作并像obj一样返回。

在主线程中,您需要通过来自worker的返回的obj重新构建您的类的实例,就这样。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接