从WebWorker同步获取数据?

Ber*_*ard 6 javascript locking synchronous web-worker webassembly

虽然我理解JavaScript本质上是单线程的,并且通常对这些事情不满意,但我想知道是否有任何方法可以让WebWorker等到主线程提供一些数据而不破坏WebWorker的调用堆栈.

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

我考虑过的其他一些解决方案:

  • 在循环中连续轮询LocalStorage,直到预定密钥上有数据.这似乎是有效的,因为即使在循环中轮询时,其他线程的LocalStorage更新应该对当前线程可见,从所有关于LocalStorage的线程安全性的讨论判断并且有多个选项卡写入相同的LocalStorage键.这种方法的缺点是它不是真正"等待",即工作线程仍然消耗在LocalStorage上的全部CPU使用率.虽然LocalStorage通常使用锁实现,但是长时间不能持有LocalStorage锁(锁被释放一次getItemsetItem返回).

  • ECMAScript 6 yield.这在这里不起作用,因为它需要调用堆栈中的所有函数(直到你想要屈服的地方)被标记为生成器函数.我想暂停我的WebWorker的地方有一个包含WebAssembly函数的调用堆栈,它不能标记为生成器函数.

  • IndexedDB的.这不起作用,因为IndexedDB不支持同步请求.

我知道这个类似的问题,但是这个问题专门讨论了这个onmessage事件,并在2012年之前被问到,yield并且引入了WebAssembly.

有没有办法以某种方式模拟WebWorker线程上的锁,否则,它会等到某些数据可用?

JF *_*ien 6

编辑:请注意,SharedArrayBuffer默认情况下,在所有主要的浏览器禁用(于2018年1月5日)响应幽灵.


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

  • 新技术:刚刚在1月的TC39会议上进入第4阶段(及时为ES2017)
  • 将无法在旧版浏览器上可靠地运行(旧版本具有不同的API,或者没有可用的实现)
  • 深奥的黑客(类似于C++内存模型)
  • 作品

出于您的目的,您希望WebWorker等待数据可用.有了SharedArrayBuffer您可以使用SPINLOOP(Atomics.load直到值的变化),但它会更好地使用Atomics.wait,直到其他工作人员向您发送Atomics.wake.这个后来的API受到Linux的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.wake(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);
Run Code Online (Sandbox Code Playgroud)

记住:阻止主线程是个坏主意!如果您这样做,您的网站将无法响应.你的问题是关于阻止一个工人,但读者可能有兴趣等待主线程.别!

最终将在WebAssembly中提供非常相似且兼容的API .这是一个早期的提案草案.当我说兼容时:我们希望WebAssembly能够SharedArrayBuffer像JavaScript 一样使用它,并且两者都能够通过它无缝地进行通信.