使用Web Worker中的可传输对象

alt*_*126 27 javascript web-worker transferable

我目前有这个代码来创建一个Web Worker:

w = new Worker("webwork.js");
w.onmessage = function(event) { alert(event.data); }
Run Code Online (Sandbox Code Playgroud)

然后是webwork.jsWeb Worker 的代码:

self.onmessage = function(event) {
    //var ss=r;  //Causes error because of undefined
    var ss="";
    for(var currProp in event) {
        ss+=("event."+currProp+"="+event[currProp]+"\n");
    }
    postMessage(ss);
}
Run Code Online (Sandbox Code Playgroud)

现在我想ArrayBuffer用这段代码传输128兆字节:

var r = new ArrayBuffer(1048576*128);
w.postMessage(0, [r]);
Run Code Online (Sandbox Code Playgroud)

既然我已经转移了变量r,我该如何从Web Worker本身访问它.我已经试过event.r,只是r,self.r和喜欢尝试添加第二个函数参数为数组其他东西ArrayBuffers,但没有任何工程.

如何从Web Worker访问传输的变量?

小智 48

sbr给出的答案有效,但它会在发送给工作人员之前生成数据的副本.对于大量数据而言,这可能会很慢.
要使用"可转移对象",您实际上将对象的所有权转移到Web工作者或从Web工作者转移.这就像通过引用传递没有复制的地方.它与正常的引用传递之间的区别在于传输数据的一方无法再访问它.

我相信你应该在你的例子中发送数据的方式是:

w.postMessage(r,[r]);  // first arg is r, not 0 as in the question
Run Code Online (Sandbox Code Playgroud)

以及在Web worker中访问它的方式:

addEventListener('message', function(event) {
    var r = event.data;
});
Run Code Online (Sandbox Code Playgroud)

在我自己的应用程序中,我需要从Web worker向主线程发送一个大型的Float64Array,而不会对副本造成性能损失.它需要大量的试验和错误以及搜索,因此我认为我应该将这个示例包含在其他任何遇到类似问题的人身上.
这是在工作者端工作的代码(arr是我的Float64Array):

self.postMessage(arr.buffer, [arr.buffer]);
Run Code Online (Sandbox Code Playgroud)

在接收主线程上我有:

theWorker.addEventListener('message', function(ev) {
    var arr = new Float64Array(ev.data);  // just cast it to the desired type - no copy made
    // ...
});
Run Code Online (Sandbox Code Playgroud)

请注意,这适用于Chrome,但可能不是此日期的大多数其他浏览器(尚未尝试过.)

此外,如果您想要发送除大型数组之外的其他信息,您可以执行以下操作:

self.postMessage({foo:"foo", bar:arr.buffer}, [arr.buffer]);
Run Code Online (Sandbox Code Playgroud)

在接收(在此示例中为主)线程:

theWorker.addEventListener('message', function(event) {
    var foo = event.data.foo;
    var arr = new Float64Array(event.data.bar);  // cast it to the desired type
    // ...
});
Run Code Online (Sandbox Code Playgroud)

  • 这个答案比接受的答案要好,因为它更好地解释了第二个数组参数的用途. (3认同)
  • 感谢您实际展示了除了传输缓冲区之外如何发送可复制数据。我在 MDN 上找不到合适的例子。 (2认同)

Coo*_*Cmd 38

PostMesage(aMessage, transferList)
Run Code Online (Sandbox Code Playgroud)

transferList您必须指定transferable对象,其中包含aMessage:

var objData =
{
    str: "string",
    ab: new ArrayBuffer(100),
    i8: new Int8Array(200)
};
objWorker.postMessage(objData, [objData.ab, objData.i8.buffer]);
Run Code Online (Sandbox Code Playgroud)

在另一边:

self.onmessage = function(objEvent)
{
    var strText = objEvent.data.str;
    var objTypedArray = objEvent.data.ab;
    var objTypedArrayView = objEvent.data.i8;
}
Run Code Online (Sandbox Code Playgroud)

  • 有谁知道这是转让所有权还是复制?我试过了,看起来它转移了所有权。 (2认同)
  • @Pawel 你能详细说明如何来回发送吗?收到数组后,如果您再次尝试 postMessage,浏览器会抱怨“索引 0 处的 ArrayBuffer 已被绝育”。 (2认同)