'Clear all alarms before the user closes all the windows in Google Chrome

I have a Chrome extension that creates an alarm when a button is pressed and, when the alarm is done, the extension creates a notification. But, I want all the alarms to be removed when the user closes all the windows. Initially, I tried to clear all the alarms when the user opens its first window:

// background.js

chrome.windows.onCreated.addListener((window) => {
    chrome.windows.getAll((windows) => {
        if (windows.length == 1) {
            chrome.alarms.create('CLEAR_ALL_ALARMS', {delayInMinutes: 0});
        }
    });
});

chrome.alarms.onAlarm.addListener((alarm) => {
    if (alarm.name === 'CLEAR_ALL_ALARMS') {
        chrome.action.setBadgeText({ text: '' });
        chrome.alarms.clearAll();
    }
});

This solves the problem when the user creates an alarm, closes all the windows, then returns back before the alarm is done. But, when the user closes all the windows and does not return back for a considerable amount of time (i.e. when the alarm has finished its time), then, when the user returns, the queued notification by the finished alarm will fire up before the extension can clear the said alarm. So now my goal is to clear all the alarms when the user closes all the windows, not when it first open a window. How do I do this?



Solution 1:[1]

I don't think there is an infallible way to do this, but you could try to proceed in this way:
In the alarms handler within your background script (or in Service Worker) compare alarm "when" property with the current time. If the difference is greater than a certain "gap" time (decided a priori) you will ignore that alarm as it is considered obsolete otherwise you will honor it by creating the notification.

I suggest you set this time gap not less than minute as the alarms API are not Swiss watches and in any case it is documented that they can be deferred in case of force majeure.

If you reopen the browser after the expiration of an alarm, but not before the time gap has spent, you will probably see the notification relating to that alarm.

const ac = chrome.action;
const al = chrome.alarms;

ac.onClicked.addListener(async tb => {
    var newAlarmId, newAlarmTime;
    var txt = await ac.getBadgeText({'tabId': tb.id})
    newAlarmId = (txt == '' ? 1 : Number(txt) + 1);
    al.create('myAlarm' + newAlarmId, {when: Date.now() + 180000 } );   //alarms trigger in 3 minutes.
    ac.setBadgeText({tabId: tb.id, text: '' + newAlarmId})
});

const gap = 60000; //1 minute
al.onAlarm.addListener(alarm => {
    var an = alarm.name;
    if (an.startsWith('myAlarm')) {
        if (an.when >= Date.now() - gap )   //not too old
            console.log('Go with notification for alarm with name: ' + an);
        else    // too old
            console.log('alarm with name: ' + an + 'is too old, so no notification')
    }
})

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 Robbi