3

我正在和网络工作者一起玩。我有一些中等规模的数据对象,它们的操作需要相当长的时间。Web Worker 似乎是并行化这些操作的好方法,但我发现很难选择将它们传递给 Web Worker 的最佳方式。Web Worker 可以序列化和反序列化对象,但这会让它们失去类方法。我当然很想用他们的方法。

问题是什么是处理重新附加方法的好方法?显然,可以将方法复制到传入的对象上,但这意味着我们知道我们得到了什么样的对象。为了使事情变得更加困难,一些对象包含其他类的数据,这意味着我们需要将方法重新附加到这些类。首先想到的是为每个将 JSON 对象作为参数的类实现一个替代构造函数。然后,备用构造函数可以递归调用任何数据成员的 JSON 构造函数。

那么一开始我如何选择正确的构造函数的问题我想到的方法包括:

  1. 为每个类实现不同的网络工作者(尴尬)
  2. 实现调用正确构造函数的工厂方法,(暗示我在发送之前直接指定发送对象的类)(更好,但仍然尴尬)
  3. 实现一些类型猜测功能来确定顶级对象是哪个类。(-_-)

有人有更好的主意吗?

4

4 回答 4

1

选项 2 听起来是最好的选择。如果你在你的类上建立一个知道如何序列化和反序列化自己的标准方法集,以及一个全局序列化助手,你可以让这件事变得简单。考虑以下代码:

反序列化 = (function() {

    var 注册表 = {};

    var 反序列化 = 函数(obj){
        var cls = obj['class'];
        var 数据 = obj['data'];

        var fn = 注册表[cls];
        返回 fn(数据);
    };

    反序列化.registerClass(名称,fn){
        注册表[名称] = fn;
    };

    返回反序列化;
});

以及以下课程:

/**
* 关于一个人的信息
*/
var Person = function(firstName, lastName, age, phoneNumbers) {
    this.firstName = 名字;
    this.lastName = 姓氏;
    this.age = 年龄;
    this.phoneNumbers = phoneNumbers;
};

Person.serializeName = '人';

/**
* 序列化一个人的实例
*/
Person.prototype.serialize = function() {
    返回 {
        “类”:Person.serializeName,
        '数据': {
            'first_name': this.firstName,
            'last_name', this.lastName,
            '年龄': this.age,
            'phone_numbers': this.phone_numbers.map(function(number) { return number.serialize(); })
        }
    };
}

/**
* 反序列化一个人的实例
*/
Person.deserialize(数据) {
    var phoneNumbers = data.phone_numbers.map(反序列化);
    返回新人(data.first_name,data.last_name,data.age,phoneNumbers);
};

deserialize.register(Person.serializeName, Person.deserialize);

您可以使用 序列化任何 Person 实例data = person.serialize();,将其发送给您的工作人员,并使用反序列化它以person = deserialize(data);序列化格式生成数据的任何内容都是可反序列化的,并且在反序列化之前您不必知道它是哪种类 - 携带类型连同数据。嵌套数据类型也是可能的,如person.phoneNumbers. PhoneNumber 类的实现可能是:

/*
* 电话号码
*/
var PhoneNumber = function(number, numberType) {
    this.number = 数字;
    this.numberType = numberType;
}

PhoneNumber.prototype.serializeName = 'PhoneNumber';
/**
* 序列化一个电话号码的实例
*/
PhoneNumber.prototype.serialize = function() {
    返回 {
        “类”:PhoneNumber.serializeName,
        '数据': {
            '数字':this.number,
            'number_type': this.numberType,
        }
    };
}

/**
* 反序列化一个电话号码的实例
*/
PhoneNumber.deserialize(数据) {
    var phoneNumbers = data.phone_numbers.map(反序列化);
    return new PhoneNumber(data.first_name, data.last_name, data.age, phoneNumbers);
};

deserialize.register(PhoneNumber.serializeName, PhoneNumber.deserialize);

同样,用于反序列化数据块的所有信息都在该块中,因此将数据发送到deserialize将给您返回某个实例。如果您在普通代码和 webworker 代码中重复使用您的类,您将获得与您开始使用的实例相同的副本。

于 2013-03-22T00:59:30.793 回答
1

显然,我真正需要做的就是了解__proto__Javascript 的属性。这可以在将对象传递给 Web Worker 或从本地存储检索后重新建立对象的类方法的可用性。

function reattachMethods(serialized,originalclass) {
    serialized.__proto__ = originalclass.prototype; 
}

上述一些解决方案的问题是,即使您已经拥有正确格式的所有数据,您最终还是会重新制作/复制对象。如果您有一个包含 n 个元素的对象,那么在 n 个对象被序列化并从浏览器发送到 web worker 之后,需要将 n 个元素复制到新对象中。这显然不理想。双下划线 proto 是一项非标准功能,已在所有主要浏览器中实现,并已被宣布为下一个 javascript 标准的一部分。

于 2013-07-08T04:41:55.860 回答
0

最直接的方法是将纯数据传递给 Web Worker,然后使用该数据实例化您在 Web Worker 内部进行实际工作所需的任何自定义对象(例如类)。这些自定义类的代码必须可供网络工作者使用。

然后,您不会尝试跨主线程和 Web 工作者之间的边界传递方法(这不是您真正可以做的事情)。

您的选项 2 听起来最接近此。将数据传递给 web worker,让它要么拥有知道从该数据创建什么样的对象的代码,要么使用可以分析数据并为需要完成的工作制作正确类型的对象的工厂函数。

我认为选项 1 的额外复杂性没有任何理由。您需要为每个要并行运行的执行线程使用单独的 web 工作者,但对于不同类型的工作不需要不同的 web 工作者。如果给出正确的代码,任何给定的网络工作者都可以做任何类型的工作。

我不喜欢在您的选项 3 中“猜测”。如果您希望网络工作者知道要创建什么类型的对象,那么将该数据显式传递给网络工作者。没有理由猜测。

于 2013-03-22T00:21:28.137 回答
0

我认为 vkThread 插件

http://www.eslinstructor.net/vkthread/

可以帮助您解决这个问题。使用此插件,您可以在单独的线程(worker)中执行任何函数(包括对象的方法)。

另一个有用的插件是 JSONfn

http://www.eslinstructor.net/jsonfn/

它可以用成员函数序列化 javascript 对象。

希望这可以帮助,

——瓦迪姆

于 2013-07-31T05:44:37.307 回答