【问题标题】:Transferable custom classes with ES6 web workers使用 ES6 网络工作者的可迁移自定义类
【发布时间】:2018-03-16 12:35:57
【问题描述】:

在 Javascript ES6 中,在浏览器中,我想使用“Transferable”接口将自定义类对象传输到 Web Worker。这可能吗?我可以找到有关 ArrayBuffer 对象的文档,但不能找到自定义类对象。

这不是 How to pass custom class instances through Web-Workers? 的重复,因为我的问题专门针对 Transferable 接口。我想将我的自定义类实例传递给工作人员而不复制它。

【问题讨论】:

  • 该线程与 Transferable 接口无关。关键是将类实例传递给worker而不复制它。
  • 不,您无法自己制作可转移对象。那些ArrayBuffers很特别,在被转移后访问时会抛出异常。
  • 这是不可能的。 Transferable 仅适用于 ArrayBuffer,因为只有使用它们才有意义。你可以做这样的事情的唯一方法是制作代理对象,但它仍然是有限的和异步的。 ArrayBuffer 是原始数据,简单易序列化。对象很复杂,有闭包、来自和指向同一堆中其他对象的引用和循环引用。

标签: ecmascript-6 web-worker transferable


【解决方案1】:

我已经多次以不同的方式解决了这个问题。很抱歉,您对本次查询的特定版本的答案肯定是

有几个原因。

  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));

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

【讨论】:

    猜你喜欢
    • 2022-07-14
    • 2011-11-23
    • 2016-04-18
    • 2020-07-14
    • 2021-08-11
    • 2011-11-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多