虽然我理解JavaScript本质上是单线程的,并且通常对这些事情不满意,但我想知道是否有任何办法让WebWorker等到主线程提供一些数据而不破坏调用堆栈WebWorker。
由于这是一个有趣的项目,我可以使用在旧浏览器上无法可靠运行的新技术和新东西,只要它们有效,我就不会介意深奥的黑客攻击。
我考虑过的其他一些解决方案:
在循环中连续轮询LocalStorage,直到预定密钥上有数据。这似乎是有效的,因为其他线程的LocalStorage更新应该对当前线程可见,即使在循环中轮询,从所有discussions判断有关LocalStorage的线程安全性并让多个选项卡写入同一LocalStorage键。这种方法的缺点是它不是真的等待#34;即工作线程仍然消耗在LocalStorage上的全部CPU使用率。虽然LocalStorage通常使用锁实现,但是长时间不能持有LocalStorage锁(锁定在getItem
或setItem
返回后释放)。
ECMAScript 6 yield
。这在这里不起作用,因为它需要调用堆栈中的所有函数(直到你想要屈服的地方)被标记为生成器函数。我想暂停我的WebWorker的地方有一个包含WebAssembly函数的调用堆栈,它不能被标记为生成器函数。
索引资料。这不起作用,因为IndexedDB不支持同步请求。
我知道this类似的问题,但该问题专门讨论了onmessage
事件,并在2012年yield
和WebAssembly介绍之前提出了问题。
有没有办法以某种方式模拟WebWorker线程上的锁,或者其他方式,以便它等到某些数据可用?
答案 0 :(得分:6)
修改:请注意SharedArrayBuffer
为disabled by default in all major browsers(2018年1月5日)以回复Spectre。
JavaScript SharedArrayBuffer听起来非常适合您:
出于您的目的,您希望WebWorker等待数据可用。使用SharedArrayBuffer
,您可以使用自旋循环(Atomics.load
直到值更改)但最好使用Atomics.wait
,直到其他工作人员向您发送Atomics.wake
。后来的API受到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.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);
请记住:阻止主线程是一个坏主意!如果您这样做,您的网站将无法响应。你的问题是关于阻止一个工人,但读者可能有兴趣等待主线程。唐'!吨
非常相似且兼容的API eventually be available in WebAssembly。 Here's an early draft proposal。当我说兼容时:我们希望WebAssembly能够使用与JavaScript相同的SharedArrayBuffer
,并且两者都能够通过它无缝地进行通信。