JavaScript 事件循环和网络工作者
The JavaScript Event Loop and Web Workers
所以我和一位同事就 JavaScript 事件循环和 Web Worker 的使用进行了长时间的交谈。在单个Web页面中,不同的Web Worker有不同的栈、堆和消息队列,形式here,具体为:
A web worker or a cross-origin iframe has its own stack, heap, and message
queue. Two distinct runtimes can only communicate through sending messages via
the postMessage method. This method adds a message to the other runtime if the
latter listens to message events.
但是所有的消息都是在同一个事件循环中执行的,还是每个 Web Worker 都有自己的事件循环?
我问这个是因为我在一个页面中有两个 Web Worker,一个按顺序执行计算量很大的操作,而另一个只处理 WebRTC 连接。
我不会详细介绍,但在我看来,计算量大的 Web Worker 从 JavaScript 事件循环中占用了如此多的计算时间,而另一个 Worker 只需要保持连接处于活动状态(通过heartbeat 我想)无法这样做,连接最终会丢失。
这就是我所相信的。如果不是这种情况,并且两个 Web Worker 在不同的事件循环上工作,那么我无法解释为什么当计算 Web Worker 的负载很重时连接会丢失(当负载很轻时连接不会丢失)。
每个工人都有自己的事件循环。来自 the specification:
Each WorkerGlobalScope
object has a distinct event loop, separate from those used by units of related similar-origin browsing contexts.
然后 here:
The global scope is the "inside" of a worker.
...后面是前面引述中引用的 WorkerGlobalScope
接口的定义。
您的计算量大的工作人员可能会占用可用的处理时间,但它不会阻塞其他工作人员的事件循环。
我们也可以通过快速测试轻松检查:
page.html
:
<!DOCTYPE HTML "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta charset="UTF-8">
<title>Two Workers</title>
<style>
body {
font-family: sans-serif;
}
pre {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div>Fast: <span id="fast"></span></div>
<div>Slow: <span id="slow"></span></div>
<script>
(function() {
var fastWorker = new Worker("fastworker.js");
var fast = document.getElementById("fast");
var slowWorker = new Worker("slowworker.js");
var slow = document.getElementById("slow");
fastWorker.addEventListener("message", function(e) {
fast.innerHTML = e.data || "??";
fastWorker.postMessage("ping");
});
slowWorker.addEventListener("message", function(e) {
slow.innerHTML = e.data || "??";
slowWorker.postMessage("ping");
});
fastWorker.postMessage("start");
slowWorker.postMessage("start");
})();
</script>
</body>
</html>
slowworker.js
:
var counter = 0;
self.addEventListener("message", function(e) {
var done = Date.now() + 1000; // 1 second
while (Date.now() < done) {
// Busy wait (boo!)
}
++counter;
self.postMessage(counter);
});
fastworker.js
:
var counter = 0;
self.addEventListener("message", function(e) {
var done = Date.now() + 100; // 100ms
while (Date.now() < done) {
// Busy wait (boo!)
}
++counter;
self.postMessage(counter);
});
如您所见,"fast" 的数量比 "slow" 增长得更快,表明它正在处理消息。
(我本可以创建一个工作文件并在启动命令中发送延迟,但是...)
所以我和一位同事就 JavaScript 事件循环和 Web Worker 的使用进行了长时间的交谈。在单个Web页面中,不同的Web Worker有不同的栈、堆和消息队列,形式here,具体为:
A web worker or a cross-origin iframe has its own stack, heap, and message
queue. Two distinct runtimes can only communicate through sending messages via
the postMessage method. This method adds a message to the other runtime if the
latter listens to message events.
但是所有的消息都是在同一个事件循环中执行的,还是每个 Web Worker 都有自己的事件循环?
我问这个是因为我在一个页面中有两个 Web Worker,一个按顺序执行计算量很大的操作,而另一个只处理 WebRTC 连接。 我不会详细介绍,但在我看来,计算量大的 Web Worker 从 JavaScript 事件循环中占用了如此多的计算时间,而另一个 Worker 只需要保持连接处于活动状态(通过heartbeat 我想)无法这样做,连接最终会丢失。
这就是我所相信的。如果不是这种情况,并且两个 Web Worker 在不同的事件循环上工作,那么我无法解释为什么当计算 Web Worker 的负载很重时连接会丢失(当负载很轻时连接不会丢失)。
每个工人都有自己的事件循环。来自 the specification:
Each
WorkerGlobalScope
object has a distinct event loop, separate from those used by units of related similar-origin browsing contexts.
然后 here:
The global scope is the "inside" of a worker.
...后面是前面引述中引用的 WorkerGlobalScope
接口的定义。
您的计算量大的工作人员可能会占用可用的处理时间,但它不会阻塞其他工作人员的事件循环。
我们也可以通过快速测试轻松检查:
page.html
:
<!DOCTYPE HTML "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta charset="UTF-8">
<title>Two Workers</title>
<style>
body {
font-family: sans-serif;
}
pre {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div>Fast: <span id="fast"></span></div>
<div>Slow: <span id="slow"></span></div>
<script>
(function() {
var fastWorker = new Worker("fastworker.js");
var fast = document.getElementById("fast");
var slowWorker = new Worker("slowworker.js");
var slow = document.getElementById("slow");
fastWorker.addEventListener("message", function(e) {
fast.innerHTML = e.data || "??";
fastWorker.postMessage("ping");
});
slowWorker.addEventListener("message", function(e) {
slow.innerHTML = e.data || "??";
slowWorker.postMessage("ping");
});
fastWorker.postMessage("start");
slowWorker.postMessage("start");
})();
</script>
</body>
</html>
slowworker.js
:
var counter = 0;
self.addEventListener("message", function(e) {
var done = Date.now() + 1000; // 1 second
while (Date.now() < done) {
// Busy wait (boo!)
}
++counter;
self.postMessage(counter);
});
fastworker.js
:
var counter = 0;
self.addEventListener("message", function(e) {
var done = Date.now() + 100; // 100ms
while (Date.now() < done) {
// Busy wait (boo!)
}
++counter;
self.postMessage(counter);
});
如您所见,"fast" 的数量比 "slow" 增长得更快,表明它正在处理消息。
(我本可以创建一个工作文件并在启动命令中发送延迟,但是...)