2

I may have answered this question for myself but I need to sanity check...

I have one tab broadcasting to another over the broadcast channel every 500 ms. The second tab is set to receive broadcasts and print them in the console log.

Sending tab:

const crossTraffic = new BroadcastChannel('crossTraffic');

const queueInterval = setInterval(function(){
   crossTraffic.postMessage({action: 'keepalive', cTime: Date.now()});
   console.log(`cTime sent ${Date.now()}`);
    }
},500);

Receiving tab:

const crossTraffic = new BroadcastChannel('crossTraffic');

crossTraffic.onmessage = function(e){
  if (e.data.action === 'keepalive'){
      console.log(`ctime received ${e.data.cTime}`);
    }
  }

I've observed the following: no matter what I set the queueInterval time for, the receiving tab will never receive a broadcast more than once every 1,000 ms.

Is this normal behavior for the broadcast channel or is it possible to receive messages at a smaller interval than 1,000 ms?

JLowther
  • 236
  • 2
  • 9
  • 1
    I just setup a quick test. At a 500ms timer interval, the messages arrived 1 second appart. With a 1500ms interval, they either arrived 1 second or 2 seconds appart. None of them arrived with 1.5 seconds between them. Granularity looks like 1000ms... – enhzflep Jan 27 '20 at 23:21
  • @enhzflep Ah, I hadn't tested over 1,000 ms so thanks for checking. That seems to confirm what I had suspected. I'll have to put together a queuing system if I want better consistency. Thanks much! – JLowther Jan 27 '20 at 23:29
  • @enhzflep Bonus followup question: I get the same results when changing the above code to set and get from localStorage. Do you see the same (if you have time to check, I mean)? Tested both above and below 1,000ms and it seems to behave exactly the same as the broadcast channel in this regard: will only update once every second, no matter what. – JLowther Jan 27 '20 at 23:43

1 Answers1

3

This is a different issue than I thought...

Turns out that tabs that aren't the focus (at least in Chrome) are limited to one update per second. If I open separate windows and have one broadcast to the other, each message arrives at whatever interval I select (tested at 100ms).

Here's the modified code I used for testing on the sending window/tab:

const crossTraffic = new BroadcastChannel('crossTraffic');

var queueInterval;
var count = 0;

  queueInterval = setInterval(function(){
       count++
        if (count >= 100){
            clearInterval(queueInterval);
          }
       crossTraffic.postMessage({action: 'keepalive', cTime: Date.now(), count: count});
       console.log(`cTime sent ${Date.now()}`);
        }
    },100);

And the modified receiver:

const crossTraffic = new BroadcastChannel('crossTraffic');

crossTraffic.onmessage = function(e){
  if (e.data.action === 'keepalive'){
      console.log(`ctime received ${e.data.cTime}, #${e.data.count}`);
    }
  }

You'll observe that if both sender and receiver are tabs in the same window, the receiver will be logging them only once per second, yet all 100 messages will be sent and received.

Then, pull one of the tabs out into its own window and place them side by side, watching their logs: the message will send and receive at a 100 ms interval.

Overall, excellent news as I was afraid the broadcast channel had some strict limitations I was unaware of.

Now to determine how to force background tabs to update more than once per second...

JLowther
  • 236
  • 2
  • 9
  • 2
    Yes, BroadcastChannel, like other MessageChannels, are actually the fastest way to schedule events (faster than setTimeout). An easier way to demonstrate this is [by using iframes](https://jsfiddle.net/jtrczkhw/) (though BroadcastChannel won't work in StackSnippet's null-origined one, but [windows channel](https://jsfiddle.net/rahu86sm/) would). And to avoid that blur limitation you can use this [web audio based timer](https://stackoverflow.com/questions/40687010/canvascapturemediastream-mediarecorder-frame-synchronization/40691112#40691112) – Kaiido Jan 28 '20 at 03:32
  • @Kaiido I believe that might do the trick (better than a webworker). Is there a means to trigger it on focusout? I might try something like that as that'll ensure each tab is still responsive to broadcast channel requests. – JLowther Jan 28 '20 at 04:00
  • 1
    Yes sure, you just have to listen for [visibilitychange event](https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilitychange_event), but that might be just as easy to always use this timer. – Kaiido Jan 28 '20 at 04:54