我有一个网络工作者 https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/basic_usage。我希望用它定期发出网络请求。我特别想要的一件事是即使主 JS 执行线程被阻塞(例如被 window.alert),也可以发出这些请求。我使用的是 Chrome 38。
但是,当我尝试在工作线程中发出网络请求时,请求似乎被 UI 线程阻止。这是一个人为的例子来说明这个问题:
base.js:
var worker = new Worker("/worker.js");
setTimeout(function() {
console.log("begin blocking");
var startDt = new Date();
var blockPeriod = 5000;
var a;
// Obviously we'd never actually do this, but this while loop
// is a convenient way to create the problem case (a blocked main
// thread).
while ((new Date() - startDt) < blockPeriod) {
a = 0;
}
console.log("stop blocking");
}, 3000);
工人.js:
var requestInterval = 1000;
var sendRequest = function() {
console.log("Send request interval");
var request = new XMLHttpRequest();
request.open("GET", "/ping", true);
request.onload = function() {
if (request.status === 200){
console.log(request.responseText)
} else {
console.log(request.status)
}
};
request.onerror = function() {
console.log("error")
};
request.send();
setTimeout(sendRequest, requestInterval);
}
sendRequest();
我看到的结果是,我们看到成功的 HTTP 请求持续三秒钟,直到阻塞开始。此时,在阻塞结束之前我们看不到任何记录到控制台的内容,此时我们会看到 5 个“发送请求间隔”,后面跟着 5 个响应日志,如下所示:
Send request interval
{"pong": true}
Send request interval
{"pong": true}
Send request interval
{"pong": true}
Send request interval
{"pong": true}
begin blocking
stop blocking
5x Send request interval
5x {"pong": true}
Send request interval
{"pong": true}
我还在服务器日志中看到,在该阻塞时间内没有发出任何请求,那么这五个请求在阻塞期结束时大致同时收到。
鉴于“发送请求间隔”连续发生五次,工作人员显然正在继续执行:如果没有,它就无法进入下一次迭代的队列。我还发现,如果我通过触发 window.alert 来阻止而不是循环旋转,我会从开头获取日志消息sendRequest
以 1 秒为间隔,然后在我停止阻塞后立即批量获取响应处理程序日志消息。
在 Firefox 中,后台线程似乎在这种情况下完全停止(在阻塞期间我没有得到同一批的五个请求排队)。然而,在这种情况下我只针对 Chrome(我最终想使用 WebSockets,它甚至不能在 Firefox Workers 中工作),所以我对此并不真正感兴趣。
所有这些加在一起,这让我相信 Web Workers 中的某些活动类会被生成线程阻止,而有些则不会(我最初在 WebSockets 中看到了相同的行为)。具体来说,我想知道(如果有人知道的话):
- Chrome 中哪些 Worker 活动被主线程阻止?
- 有办法解决这个问题吗?我非常希望能够在 Worker 中建立 WebSocket 连接,然后继续来回 PING/PONG,即使某些内容(例如警报/确认)确实阻塞了主线程。
- 这都是废话吗,我只是在做傻事吗?