16

I have a question about chrome extension install/update event. If I add the onInstalled event listener in a top level code in the background script, is there a time frame in which my event listener will catch that event?

I'm asking this, because my demos showed that if I have some logic that executes before I hook onInstalled listener, it looks like it will never be executed, like that event happens in the meantime.

Can someone explain to me with more details how this event works, in the context of other logic in the background script, or point me to some documentation, since I haven't been able to find anything useful.

Thanks!

Update @Noam Hacker : Due to a company policy I can't post any real code here, but I have some pseudo code that illustrates my problem :

/**
 * setup in which I miss onInstalled event
 */
function firstLogicThatRunsOnBackgroundLoad() {
    // perform some logic

    // perform some asynchronous operations via generators and promises
    // which can take a while

    chrome.runtime.onInstalled.addListener(function (details) {
            if (details.reason == "install") {
                // this logic never gets executed
            } else if(details.reason == "update") {
                // perform some logic
            }
        });
}

/**
 * setup in which I catch onInstalled event 
 */
function firstLogicThatRunsOnBackgroundLoad() {
    chrome.runtime.onInstalled.addListener(function (details) {
            if (details.reason == "install") {
                // this logic executes
            } else if(details.reason == "update") {
                // perform some logic
            }
        });

    // perform some logic

    // perform some asynchronous operations via generators and promises
    // which can take a while
}
vladamon
  • 297
  • 1
  • 3
  • 11
  • do you have any sample code of your background script? – Noam Hacker Nov 15 '16 at 15:50
  • what if you put your primary logic inside the listener function? `chrome.runtime.onInstalled.addListener(function (details) { //perform logic you'd like to do first... //install/update logic... }` – Noam Hacker Nov 16 '16 at 21:35
  • @NoamHacker If I put some logic that I want to execute first inside the listener function, my testing showed that there is no guarantee that this logic will be executed first, if there is some other logic in the background. – vladamon Nov 17 '16 at 09:13
  • 1
    I see that you mention async generators/promises. Do you also execute `chrome.runtime.onInstalled.addListener(...)` async, meaning inside a generator/promise or a callback? In my experience the listeners needs to be registered *synchronously* when the "top-level" background script executes. The `onInstalled` callback execution will of course be async though, as the event is triggered only after the initial synchronous script execution. – Joel Purra May 10 '17 at 06:15
  • 2
    @JoelPurra you are right, the listeners need to be registered synchronously in a top level code in background script. It's been a while since I had this problem, nevertheless the problem was that I was adding some listeners outside the top level code, via functions that were orchestrated via promises, which caused onInstalled event to execute before the logic for handling this event is hooked. – vladamon May 10 '17 at 12:05

3 Answers3

19

onInstalled listeners catch events in these situations:

when the extension is first installed, when the extension is updated to a new version, and when Chrome is updated to a new version.

Since this is all asynchronous it will happen in the background, and according the documentation, fires immediately at any of these situations. Review asynchronous programming for some clarity on this.

link to documentation

According to your question it seems like you want help executing code in the right order. This answer provides a helpful framework for your case (using the reason attribute).

chrome.runtime.onInstalled.addListener(function(details){
    if(details.reason == "install"){
        //call a function to handle a first install
    }else if(details.reason == "update"){
        //call a function to handle an update
    }
});
Community
  • 1
  • 1
Noam Hacker
  • 4,671
  • 7
  • 34
  • 55
  • 1
    I'm aware of this, that the onInstalled event is fired when the extension is installed, updated, or when the Chrome is updated to a new version. I was more curios about the flow, and the timeframe in which I can catch that event, since I noticed that if I have some logic that runs before I hook onInstalled listener, my listener never catches that event. – vladamon Nov 16 '16 at 08:27
  • I seem to be running into a similar issue. When I do a "Load unpacked" it always triggers, but once I package my code and do some closure, the onInstalled triggers about half the time without any error in the console. I also have some code running before the listener is initiated, so I'm moving my code to make sure the listener is set early in the process. – SHamel Aug 13 '19 at 14:44
5

I needed to figure this out too. While I didn't find anything authoritative, I did throw a couple of console.time() statements in my background script.

Code was something like this:

console.time('onInstall event');
console.time('first function');

chrome.runtime.onInstalled.addListener(details => {
  console.timeEnd('onInstall event');
});

// 7 module imports

someSyncFunction() // console.timeEnd('first function') is called in the first line in this function

Then I just loaded/reloaded the extension (unpacked, in dev mode) a few times. onInstall seems to pretty reliably fire within the first 50ms, while the first function happens w/in the first ms. Here are the results:

(First function, onInstall event)
(.282ms, 47.2ms)
(.331ms, 45.3ms)
(.327ms, 49.1ms)
(.294ms, 45.9ms)
Brandon
  • 7,736
  • 9
  • 47
  • 72
4

Given that the document says

“Listeners must be registered synchronously from the start of the page.”

and

“Do not register listeners asynchronously, as they will not be properly triggered.”

, it seems they guarantee every synchronously-attached listener not to miss any, no matter how long it takes to evaluate your code. And this would be done by Chrome firing events after evaluating your entire code.

My hypothesis is that onInstalled actually works like onInitialized. No test data, though.