Chrome Extension Event Task Queue

41 views
Skip to first unread message

Moe Bazzi

unread,
May 27, 2024, 4:53:15 PMMay 27
to Chromium Extensions
Hey all, I am wondering which JavaScript task queue do Chrome extension events use (e.g. chrome.tabs.onUpdate)? 

The reason I ask is because I want to batch multiple of the same events into one handler. For example, lets say you have 2 tabs in a tab group, then you select them both, then remove them from the tab group, two consecutive chrome.tabs.onUpdate events will be dispatched. I would like my extension to know that the user ungrouped 2 tabs at the same time, rather than have my extension think they ungrouped 2 tabs at separate times. This is crucial for my extension's logic.

Currently, I am batching the events by using a 1-second setTimeout, which seems to be working fine. Here is an example:
`
const batchedEvents = []
chrome.tabs.onUpdate.addListener((tabId, changeInfo, tab) => {
  batchedEvents.push([tabId, changeInfo, tab])
  setTimeout(() => {
    // loop through batched events and do app logic...
    batchedEvents = []
  }, 1)
})
`

If I use a 0-second timeout, then this doesn't work. I am trying to understand why is this the case, from the perspective of the JavaScript event loop and the micro/macro task queue.

Moe Bazzi

unread,
May 27, 2024, 5:10:34 PMMay 27
to Chromium Extensions
UPDATE: 

its not guaranteed that a 1-second timeout will be able to batch multiple events. This requires me to use a longer timeout, which isn't ideal since this is deterministic behavior. 

woxxom

unread,
May 28, 2024, 2:10:52 AMMay 28
to Chromium Extensions, Moe Bazzi
It's not directly related to the JS event loop queue because `chrome` events are dispatched from the browser process, it's a different process and it's not using JavaScript. Each message arrives as a separate JS task in the extension and usually it happens quickly, but since they are dispatched separately there's no guarantee the extension will receive the next message in the next JS event task in which the callback of setTimeout(fn, 0) runs. Theoretically (depending on how it's implemented) if the browser is busy the pause may be longer. Practically, using timeouts is not reliable, but there's probably no other way, so you'll need to find a small value that works. For example, physically clicking a mouse button takes at least 50ms, so using 35ms for a delay is arguably safe.

A proper solution is to fix the API, e.g. you can suggest in WECG to add a value to changeInfo in chromee.tabs.onUpdated to indicate this is a batch operation from tab groups.

woxxom

unread,
May 28, 2024, 2:12:42 AMMay 28
to Chromium Extensions, woxxom, Moe Bazzi
>  its not guaranteed that a 1-second timeout will be able to batch multiple events

Oh, I see. In that case there's probably no reliable solutions. You can try observing other tab events to infer from them what actually happens.

Roberto Oneto

unread,
May 28, 2024, 8:20:58 AMMay 28
to Chromium Extensions, woxxom, Moe Bazzi
Maybe I didn't understand your problem correctly, but in my opinion,  you have to choose the right timeout time based on the time that passes between the removal of one tab and the other.
Furthermore, every time a tab is removed this timeout must be reinitialized.

var batchedEvents = [];
var timeOutOnRemoved;
chrome.tabs.onUpdate.addListener((tabId, changeInfo, tab) => {
  batchedEvents.push([tabId, changeInfo, tab])

  clearTimeout(timeOutOnRemoved);
  timeOutOnRemoved = setTimeout(() => {
    // loop through batched events and do app logic...
    //...
    batchedEvents = []
  }, 50)
})
Reply all
Reply to author
Forward
0 new messages