Search code examples
javascriptweb-worker

JS Web Worker is a macro task?


In which queue browsers handle WebWorkers? Microtasks, Macrotasks, or a dedicated one?

We know that things such as setTimeout and setInterval are macrotasks, and Promises are microtasks. But I can't find any information regarding WebWorkers and the message event.

var worker = new Worker('doWork.js');

worker.addEventListener('message', function(e) {
  console.log('Worker said: ', e.data);
}, false);

worker.postMessage('Hello World');

Solution

  • This question seems to come from a few misunderstandings.


    First a bit of hair splitting on nomenclature, but there is nothing named "macro-task". Only "task" and "microtask" are part of the HTML specs, responsible for the Event loops in a browser.
    This point has some sense since you need to understand that microtasks are just normal tasks that get executed at a special moment in the event-loop.

    Basically, after each task execution, the browser will perform a microtask endpoint which will check if there are pending microtasks to get executed.

    This is the only difference between a microtask and a task.

    So asking if something runs in a microtask or in a task makes very little sense. To make something run in a microtask all you need is to call it from queueMicroTask()*, but once again, that won't change anything.


    The creation of a Worker is asynchronous (it needs to fetch the script) and thus does span on multiple tasks, on different processes, and on different event loops (though they use the same processing model).

    So saying if it runs in a microtask... The synchronous part could.

    queueMicrotask( () => {
      // Worker instance is created from a micro-task...
      const worker = new Worker('data:application/javascript,const foo="bar";');
    } );


    Now, IMM the most interesting point of this question is about the message event.

    Indeed, we already saw that we only have tasks, however what we didn't say is that there are several task queues and most importantly, all task queues don't have the same priority!

    There is an ongoing proposal to give control over these priorities to web-devs, but that's still a proposal.

    I must admit that for the time being what happens is not always clear science to me, but basically the posted message task source comes from one of the tasks queues with highest priority we have access to (IIRC after animation frames).

    Concretely this does mean that if you schedule two asynchronous tasks from the same event loop, the message event should win, even though it's been called after:

    setTimeout( () => console.log( 'timeout' ), 0 );
    onmessage = e => console.log( 'message' );
    postMessage( '', '*' );

    *which is also available in Workers, so Promises are not the only way to run microtasks in a Worker.