I have a Web Worker. I wish to make periodic network requests with it. One thing I particularly want is to make these requests even if the main JS execution thread is blocked (eg by a window.alert). I'm using Chrome 38.
However, when I attempt to make network requests in the worker, the requests appear to be blocked by the UI thread. Here is a contrived example to illustrate the problem:
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);
worker.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();
The result I'm seeing is that we see successful HTTP requests for three seconds, until the blocking begins. At this point, we don't see anything logged to the console until the blocking ends, at which point we see five "Send request interval"s followed by 5 logs of the response, like so:
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}
I also see in my server logs that no requests are made in that blocking time, then those five requests are all received roughly simultaneously at the end of the blocking period.
Given that "Send request interval" occurs five times in a row, the worker is evidently continuing to execute: if it weren't, it wouldn't make it through to queue up the next iteration. I've also found that if I block by triggering a window.alert instead of spinning in a loop, I get the log messages from the beginning of sendRequest
at 1 second intervals, and then get the response handler log messages in a large batch as soon as I stop blocking.
In Firefox, the background thread seems to stop entirely in this case (I don't get that same batch of five requests queued up during the blocked period). However, I'm only targeting Chrome in this case (and I ultimately want to use WebSockets which don't even work in Firefox Workers), so I'm not really interested in that.
All added together, this leads me to believe that there are some classes of activity in Web Workers which are blocked by the spawning thread, and some which are not (I originally saw this same behavior with WebSockets). Concretely, I'd like to know (if anyone does know):
- What Worker activity is blocked by the main thread in Chrome?
- Is there a way to work around this? I'd very much like to be able to able to establish a WebSocket connection in a Worker, and then continue to PING/PONG back and forth, even if something (such as an alert/confirm) does block the main thread.
- Is this all nonsense, and am I just doing something stupid?