Website workers suddenly shut down

I started working with the webmaster on chrome, and it had a simple function that was called multiple times using setTimeout . Surprisingly, the web worker quit after the function was called about 1000 times. Can anyone explain why? I think chrome does some optimization.

webworker.js

 function hi() { postMessage('1'); setTimeout(hi, 1); } hi(); 

main.js

 var blob = new Blob([code]); var blobURL = window.URL.createObjectURL(blob); var worker = new Worker(blobURL); worker.onmessage = function(data) { console.log(data.data); // gets called around 1000 times and done }; 

EDIT: Reproduced in violin: http://jsfiddle.net/meovfpv3/1/ It seems like it takes a long time for the onmessage callback to stop firing, as fast as a few seconds and up to +5 minutes

+7
javascript google-chrome web worker
source share
3 answers

Here is my best guess about what is happening. By publishing a message from a web worker every 1 ms, you require that the main thread process each sent message for 1 ms.

If the main thread cannot process the message within 1 ms, you still send it a new message, even if it has not finished processing the last message. I would suggest that this puts it in a queue of messages awaiting processing.

Now that you are sending messages from a web worker faster than they can be processed, this queue of unprocessed messages will become more and more. At some point, Chrome is going to crack its hands and say: โ€œThere are too many messages in the queue,โ€ and instead of queuing up new messages for processing, he omits them.

That is why if you use a reasonable number in a timeout such as 100 ms, the message has enough time to process before sending the next message, and there are no problems with the raw messages.


I created jsFiddle where the worker sends the message to the main thread and the main thread sends the message back to the worker. If this process does not occur before the next message is sent, the counters in both threads will be incompatible, and the web worker will exit.

http://jsfiddle.net/meovfpv3/3/

You can see that with a reasonable setTimeout of 100 ms, all messages have enough time to process until the next message appears.

When you reduce the setTimeout value to 1 ms, the message chain does not have time to finish before the next message is sent, and the counters in each thread will eventually be canceled, disabling the if clause and shutting down the web worker.


One way to fix this problem is instead of a blind message message every 1 ms, if the latter was processed or not, only after a new message after receiving the message back from the main stream. This means that you send messages only quickly, as the main thread can handle them.


For completeness, here's a copy of the JSFiddle code:

Working:

  var counter2 = 0; var rcvd = true; function hi() { counter2++; console.log("") console.log("postMessage", counter2) postMessage(counter2); if (!rcvd) { self.close(); console.log("No message received"); } rcvd = false; setTimeout(hi, 1); } hi(); onmessage = function(e) { rcvd = true; console.log("secondMessage", e.data); } 

Main:

 var ww = document.querySelector('script[type="text/ww"]'), code = ww.textContent, blob = new Blob([code], {type: 'text/javascript'}), blobUrl = URL.createObjectURL(blob), worker = new Worker(blobUrl), counter = 0; worker.onmessage = function(e) { counter++; console.log("onmessage:", counter); worker.postMessage(e.data); } 
+5
source share

Firstly, a few observations that I can not explain, but are interesting and can be inspirational for someone:

  • @Anson - If I add jsFiddle code to Codepen (still in Chrome), there is no problem there. The onmessage just works!

  • And back to jsFiddle ... It doesnโ€™t even allow you to change setTimeout to a long break, for example, 10 seconds, so this is not the number of times the worker sends a message, how long does the onmessage before the onmessage stops firing - which has a lot of variance.

Then I found several ways to save the onmessage handler in this specific example:

  • Add a button / link in html and a handler (I used jQuery) that will complete the work on the client. Just adding this code fixes it. $("#stop").on("click",function(e){e.preventDefault();worker.terminate();});
  • Just add console.log(worker) after defining onmessage .
  • Inspired by the answer posted in the question, you can also just add window.worker = worker after defining onmessage .

Something about mentioning worker again in all cases seems to save it.

+4
source share

Are you trying to send messages every 1 ms? Then you probably wanted to use setInterval() :

 setInterval(function(){ postMessage('1'); }, 1); 

Edit: I did not see the recursion correctly, which was not there, just because I was looking for it. I would still use setInterval over setTimeout .

+1
source share

All Articles