使用ES6 Web Workers传递可转移的自定义类

10
在Javascript ES6中,在浏览器中,我想使用"Transferable"接口将自定义类对象传输到Web Worker。这是否可能?我可以找到有关ArrayBuffer对象的文档,但没有关于自定义类对象的文档。
这不是如何通过Web Workers传递自定义类实例的重复问题,因为我的问题特别涉及Transferable接口。我想在不复制它的情况下将我的自定义类实例传递给Worker。

那个线程不是关于Transferable接口的。重点是将类实例传递给工作者而不进行复制。 - atomickitten
1
不,自己无法创建可转移对象。那些 ArrayBuffer 非常特殊,因为在传输后访问会抛出异常。 - Bergi
1
这是不可能的。Transferable 只适用于 ArrayBuffer,因为只有它们被使用时才有意义。你唯一能做到类似的事情就是通过创建代理对象,但仍然受到限制且是异步的。ArrayBuffer 是原始数据,简单易序列化。对象则是复杂的,带有闭包、引用同一堆中其他对象以及循环引用等特性。 - Fathy
1个回答

6

我已经以不同的方式多次回答了这个问题。很抱歉,但是对于你提出的特定版本的问题,答案肯定是

有几个原因造成这种情况:

  1. 单个JavaScript对象通常不会在连续的内存块上分配(这在理论上可能使其可以传输)。
  2. 将普通对象/类转换为ArrayBuffer的任何代码都只会增加现有结构化克隆算法的开销,而该算法已经做得很好了。

你可以这样做,

如果你真的想这样做,虽然我不确定你是否应该这样做。

想象一个这样的类:

class Vector2 {
    constructor(existing) {
        this._data = new Float64Array(2);
    }

    get x() {
      return this._data[0];
    }
    set x(x) {
      this._data[0] = x;
    }
    get y() {
      return this._data[1];
    }
    set y(y) {
      this._data[1] = y;
    }
}

它的属性存储在数组缓冲区中,您可以传输它。但目前它的用途不大,要使其良好运作,我们需要确保它可以从接收到的数组缓冲区构造出来。这当然是可以做到的:

class Vector2 {
    constructor(existing) {
        if(existing instanceof ArrayBuffer) {
            this.load(existing);
        }
        else {
            this.init();
        }
    }
    /*
     * Loads from existing buffer
     * @param {ArrayBuffer} existing
    */
    load(existing) {
      this._data = existing;
      this.initProperties();
    }
    init() {
      // 16 bytes, 8 for each Float64
      this._data = new ArrayBuffer(16);
      this.initProperties();
    }
    initProperties() {
      this._coordsView = new Float64Array(this._data, 0, 2);
    }

    get x() {
      return this._coordsView[0];
    }
    set x(x) {
      this._coordsView[0] = x;
    }
    get y() {
      return this._coordsView[1];
    }
    set y(y) {
      this._coordsView[1] = y;
    }
}

现在,您甚至可以对其进行子类化,通过从子类传递较大的数组缓冲区,其中父类和子类属性都将适合:
class Vector2Altitude extends Vector2 {
  constructor(existing) {
    super(existing instanceof ArrayBuffer ? existing : new ArrayBuffer(16 + 8));
    this._altitudeView = new Float64Array(this._data, 16, 1);
  }
  get altitude() {
    return this._altitudeView[0];
  }
  set altitude(alt) {
    this._altitudeView[0] = alt;
  }
}

一个简单的测试:

const test = new Vector2();
console.log(test.x, test.y);
const test2 = new Vector2Altitude();
test2.altitude = 1000;
console.log(test2.x, test2.y, test2.altitude, new Uint8Array(test2._data));

为了真正利用它,您需要解决许多其他问题,并且基本上要为复杂对象实现自己的内存分配。

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