在 Web Worker 和主线程之间传递大量数据

22
有没有一种方法可以在Web Worker和主线程之间传递大量数据(多个MB)?我在一个项目中需要下载文件,稍微修改一下,然后让用户下载修改后的文件。我找到了以下几种在Web Worker和主UI之间传递数据的方式:
  1. 使用常规的postMessage方法。
  2. 使用可转移对象(仅限Chrome)
  3. 创建指向Blob的URL引用并仅发送URL(在Chrome中有效,在其他浏览器中也有效吗?)
当发送较小的对象时,我认为(1)是可行的,但是处理几MB以上的文件时,由于它被序列化并作为JSON发送,因此需要很长时间和空间。Chrome提供了一种使用可转移对象传输数据的方法,其中数据不必复制。不幸的是,这仅是Chrome的功能,否则它本来符合我的目的。
我找到的最后一种方法是从Worker中使用self.webkitURL创建指向Blob的URL,然后仅将URL引用传递给UI。这很有效,我可以把URL给用户,他们就可以下载文件。不幸的是我在Firefox中没有找到这样做的方法,这有可能吗?
还有其他方法可以用于在Worker和主线程之间传输数据吗?
2个回答

18

Firefox/Opera/Chrome目前都支持一种名为可传递对象的Web Workers,这种方式非常快速 - 也非常容易设置。在这里,我们向Web Worker发送了一个由浏览器分配的数组,该数组由Web Worker填充并返回给浏览器端。这是通过引用传递的,而不是复制:浏览器<-> Web Worker。

在浏览器端:

var huge_array = new Float32Array(BIG_HUSKY_SIZE);

// worker.postMessage(huge_array.buffer);                      // old way
   worker.postMessage(huge_array.buffer, [huge_array.buffer]); // new Trans Obj

然后在Web Worker内部:

self.onmessage = function(e) {

      var flt_arr = new Float32Array(e.data);

    //  typically you might want to populate flt_arr here

    //  now send data structure back to browser

    // self.postMessage(flt_arr.buffer);                    // old way
       self.postMessage(flt_arr.buffer, [flt_arr.buffer]); // new Trans Obj way
}

仅将数据对象放入方括号 [在此处] 中,即可提示js使用Transferable Object模式。这也适用于发送和接收包含多个变量的javascript对象,而不仅仅是类型化数组。 引用
可传输对象是不会被复制(例如使用结构化克隆之类的东西)的对象。相反,数据从一个上下文传输到另一个上下文。从调用上下文中的“版本”一旦传输到新上下文中就不再可用。例如,将ArrayBuffer从主应用程序传输到Worker时,主线程中的原始ArrayBuffer将被清除并且不能再使用。这大大提高了将数据发送到Worker的性能。

http://html5-demos.appspot.com/static/workers/transferables/index.html https://html.spec.whatwg.org/multipage/workers.html

https://developer.chrome.com/blog/transferable-objects-lightning-fast/

作为一个例子,在这个项目中我使用了Web Worker https://github.com/scottstensland/websockets-streaming-audio 来处理从服务器端到浏览器的WebSocket流媒体音频传输......正如你所看到的,js不是我的母语,那个项目只是一个概念验证,用于观看视频并合成与音频相同的信息......反之亦然......音频输入->一系列图像输出。

你从哪里得到这个引用的? - royhowie
这是Eric Bidelman(谷歌员工)的引用,它出现在我上面列出的URL顶部的“Yo dawg,what is this?”上,其父链接是http://updates.html5rocks.com/2011/12/Transferable-Objects-Lightning-Fast。 - Scott Stensland

4
根据这个WebWorkers教程,现在WebWorkers支持传递文件和Blob对象以及基本上可以使用structured clone算法的任何对象...... 或者至少是Chrome这样做了,可能是因为它实现了FileSystem API。我不知道它是否是主要原因,但我希望不是,并且事实上这个功能已经在其他浏览器中实现......能够在后台处理用户选择的文件是个好事。

不幸的是,即使它确实提高了速度,但这仍然是一次复制操作。 - Erik

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