'Chrome Alarm events keeps firing every 4 seconds

I am trying to pass a message triggered by an alarm from background.js to loader.js. Here is my code:

manifest.json:

{
"update_url": "https://clients2.google.com/service/update2/crx",

   "manifest_version": 2,
   "name": "DubX",
   "short_name": "DubX",
   "author": "Al3366",
   "description": "Automatically loads DubX on dubtrack.fm",
   "homepage_url": "https://dubx.net/",
   "version": "0",
   "browser_action": {
    "default_icon": "icons/48.png"
   },
   "permissions": ["background","alarms","tabs"],
   "background": {
      "scripts": ["background.js"],
      "persistent": false
    },
   "content_scripts": [{
      "matches": ["*://www.dubtrack.fm/*"],
      "js": ["jquery.js","loader.js"],
      "run_at": "document_end"
   }],

    "icons": { 
        "16": "icons/16.png",
        "19": "icons/19.png",
        "38": "icons/38.png",
        "48": "icons/48.png",
        "128": "icons/128.png" 
    }
}

background.js

chrome.alarms.create('hello',{delayInMinutes: 0.25});
chrome.alarms.onAlarm.addListener(function(alarm) {
    chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
        var content = {greeting: 'foo'};
        chrome.tabs.sendMessage(tabs[0].id, content);  
    });
});

loader.js:

chrome.runtime.onMessage.addListener(
    function(request, sender, sendResponse) {
        if (request.greeting === 'foo') {
            hello();
        };
    }
);
$('body').prepend('<div class="cake" style=" z-index: 2147483647; color: white; position: fixed; bottom: 54px; left: 27px; background: #222; padding: 13px; -webkit-box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.75); -moz-box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.75); box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.75); border-radius: 5px;">Waiting for Dubtrack...</div>');
function hello() {
    $.getScript('https://rawgit.com/sinfulBA/DubX-Script/master/beta.js');
    $('.cake').remove();
};

It keeps firing the hello(); function every 4 seconds. I can't find out what I'm doing wrong. Thanks in advance for your reply.



Solution 1:[1]

You're using an event page (non-persistent background page), which is unloaded after approximately 5 seconds of inactivity. Then some activity in the browser causes the background page to re-initialize and set a new alarm. So each 5 seconds that new alarm fires the handler that sends a message which makes the content script call hello().

  • Solution 1: check for some condition before invoking chrome.alarms.create.

    For example, if the real objective is to fire an alarm one time after the browser starts use onStartup event and set the alarm time with when key:

      chrome.runtime.onStartup.addListener(function() {
          chrome.alarms.create('hello', {when: Date.now() + 60*1000});
      });
    

    Note that in a published extension the interval between the next alarm and the last fired alarm is at least 1 minute even if you specify a smaller value like 15 seconds (15*1000).

  • Solution 2 (a bad one): make the background page persistent by using "persistent": true. It's bad because a persistent background page hogs the memory. However, as explained in Xan's answer, it's a perfect one in case you actually need to fire the alarm each 15 seconds.

Solution 2:[2]

Please note: it's impossible to use chrome.alarms to do things with a granularity less than a minute.

Quoting the docs:

In order to reduce the load on the user's machine, Chrome limits alarms to at most once every 1 minute but may delay them an arbitrary amount more. That is, setting delayInMinutes or periodInMinutes to less than 1 will not be honored and will cause a warning.

So in a production environment, your alarm won't fire at all or will be delayed. You're observing the development environment effect:

To help you debug your app or extension, when you've loaded it unpacked, there's no limit to how often the alarm can fire.

Despite wOxxOm's remark that a persistent background page is a "bad" solution, it's actually the optimal solution for tasks that require frequent repeated events. Reloading the event page every couple of minutes (or more frequently) is going to be a worse wastage of resources - event pages are for things that you know will not happen regularly or frequently.

You should switch to a persistent background page and use good old setInterval.

Ah, sorry, I did not immediately understand that you had a delay and not an interval. Then wOxxOm's answer fully applies.

Solution 3:[3]

I think you need to specify the alarm name for onAlarm.

chrome.alarms.create('hello', { periodInMinutes: 2.0 });

chrome.alarms.onAlarm.addListener(function(alarm) {

    if (alarm.name == 'hello') {
        // do your thing
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 hakeber