从WebWorker同步获取数据?

Obtain data synchronously from WebWorker?

虽然我知道 JavaScript 本质上是单线程的并且通常不赞成这样的事情,但我想知道是否有任何方法可以让 WebWorker 等待直到主线程提供一些数据不破坏 WebWorker 的调用堆栈。

由于这是一个有趣的项目,我可以使用新技术和在旧浏览器上 运行 不可靠的东西,我不介意深奥的 hack,只要它们有效。

我想到的其他一些解决方案:

我知道 this 类似的问题,但该问题专门讨论了 onmessage 事件,并且在 yield 和 WebAssembly 被引入之前的 2012 年被问及。​​

有没有办法以某种方式模拟 WebWorker 线程上的锁,或者以其他方式,以便等待某些数据可用?

编辑请注意 SharedArrayBufferdisabled by default in all major browsers (on January 5th 2018) in response to Spectre, and hasn't been fully re-enabled yet


JavaScript 的 SharedArrayBuffer 听起来非常适合您:

  • 新技术:刚刚 在 1 月份的 TC39 会议上进入了第 4 阶段(及时赶上 ES2017)
  • 在旧版浏览器上 运行 不可靠(旧版有不同的 API,或者没有可用的实现)
  • 深奥的技巧(similar to the C++ memory model
  • 有效

出于您的目的,您希望 WebWorker 等待数据可用。使用 SharedArrayBuffer 你可以使用自旋循环(Atomics.load 直到值改变)但是最好使用 Atomics.wait until the other worker sends you an Atomics.notify. This later API is heavily inspired by Linux's futex 并且如果你正在等待的值不是'可用。

// Main program:
var w = new Worker("worker.js")
var sab = new SharedArrayBuffer(1024);
w.postMessage(sab);
var i = new Int32Array(sab);
// Maybe wait for worker.js to message back that it's ready through onmessage?
//
// Fill i with some data!
// ...
//
// Notify one worker, at location 0, with value 1.
Atomics.store(i, 0, 1);
Atomics.notify(i, 0, /* notify count */ 1);


// worker.js:
var sab;
var i;
onmessage = function (ev) {
    sab = ev.data;
    var i = new Int32Array(sab);
}
// Maybe tell the main program we're ready through postMessage?
//
// ...
// Wait until location 0 isn't value 0
Atomics.wait(i, 0, 0);

记住:阻塞主线程是个坏主意!如果您这样做,您的网站将没有响应。您的问题是询问有关阻止工人的问题,但读者可能对从主线程等待感兴趣。不要!

非常相似且兼容,API 将 eventually be available in WebAssembly. Here's an early draft proposal。当我说兼容时:我们希望 WebAssembly 能够使用与 JavaScript 相同的 SharedArrayBuffer,并且两者都能够通过它进行无缝通信。