Persistent background page on demand or an event page that doesn't unload?

后端 未结 3 713
温柔的废话
温柔的废话 2020-11-30 10:36

I want to build a extension that behaves like a timer. It should count down the seconds when activated, but should do nothing with inactive.

The chrome.alarms API is

相关标签:
3条回答
  • 2020-11-30 11:02

    Background pages cannot be unloaded on demand, and Chrome decides Event page lifecycle for you (there is nothing you can do in onSuspend to prevent it).


    If your concern is timers, you could try my solution from this answer, which basically splits a timer into shorter timers for a "sparse" busy-wait. That's enough to keep the event page loaded and is a viable solution if you don't need to do that frequently.


    In general, there are some things that will keep an event page loaded:

    If you're using message passing, be sure to close unused message ports. The event page will not shut down until all message ports are closed.

    This can be exploited if you have any other context to keep an open Port to, for example a content script. See Long-lived connections docs for more details.


    In practice, if you often or constantly need precise, sub-minute timers, an Event page is a bad solution. Your resource gains from using one might not justify it.

    0 讨论(0)
  • 2020-11-30 11:05

    I use this function:

    function _doNotSleep() {
        if (isActive) {
            setTimeout(() => {
                fetch(chrome.runtime.getURL('manifest.json'));
                _doNotSleep();
            }, 2000);
        }
    }
    

    But the problem with such approach is that Devtools network tab polluted with this http stub.

    0 讨论(0)
  • 2020-11-30 11:14

    As mentioned in Xan's answer we can abuse messaging. There's nothing wrong about it either in case you want to temporarily prevent the event page from unloading. For example while displaying a progress meter using chrome.notifications API or any other activity based on setTimeout/setInterval that may exceed the default unload timeout which is 5-15 seconds.

    Demo

    It creates an iframe in the background page and the iframe connects to the background page. In addition to manifest.json and a background script you'll need to make two additional files bg-iframe.html and bg-iframe.js with the code specified below.

    manifest.json excerpt:

      "background": {
        "scripts": ["bg.js"],
        "persistent": false
      }
    

    bg.js:

    function preventUnload() {
      let iframe = document.querySelector('iframe');
      if (!iframe) {
        iframe = document.createElement('iframe');
        document.body.appendChild(iframe).src = 'bg-iframe.html';
      }
    }
    
    function allowUnload() {
      let iframe = document.querySelector('iframe');
      if (iframe) iframe.remove();
    }
    
    chrome.runtime.onConnect.addListener(() => {});
    

    bg-iframe.html:

    <script src="bg-iframe.js"></script>
    

    bg-iframe.js:

    chrome.runtime.connect();
    

    Usage example in bg.js:

    chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
      if (message === 'start') doSomething();
    });
    
    function doSomething() {
      preventUnload();
      // do something asynchronous that's spread over time
      // like for example consecutive setTimeout or setInterval calls
      let ticks = 20;
      const interval = setInterval(tick, 1000);
    
      function tick() {
        // do something
        // ................
        if (--ticks <= 0) done();
      }
    
      function done() {
        clearInterval(interval);
        allowUnload();
      }
    }
    
    0 讨论(0)
提交回复
热议问题