Search code examples
javascriptrace-conditionpostmessageweb-messaging-api

Does a "message" event handler process messages in a serial or concurrent fashion?


If some page A sends a sequence of messages to page B that listens for and handles them, does the event listener process those messages in a serial fashion? If it does so in concurrent fashion, I have to be careful about data races, don't I?

In particular, consider some page A (at https://a.example.com/index.html):

<script>
  const win = open('https://b.example.com/index.html');
  setTimeout(() => {
    for (let i = 0; i < 1024; i++) {
      win.postMessage(i, '*');
    }
  }, 1000);
</script>

and page B (at https://b.example.com/index.html):

<script>
  let count = 0;
  window.addEventListener('message', () => {count++});
</script>

When all messages have been processed, is page B's count variable guaranteed to have value 1024? Or is there no such guarantee, because messages are being processed in a concurrent manner and updates to the count variable may be lost?

The Web Messaging standard is not the easiest to read... It does mention queues, which seem to indicate serial (not concurrent) handling of messages, but I'd like to be sure.


Solution

  • Each MessagePort has its own queue (task source) where all the messages are queued. Then when the event loop will choose this queue, an Event will be dispatched from the queued task. The event loop will always pick the oldest task from a queue (FIFO order). Well, to be 100% technically correct, it will choose the first runnable task of the task queue, but in this particular case that's exactly the same.

    If A is the only source of a new message in B, then yes, you can be sure that the value will be 1024.