繁体   English   中英

您如何在 Chrome Extension Manifest V3 Background Service Worker 中每秒调用 function?

[英]How do you call a function every second in a Chrome Extension Manifest V3 Background Service Worker?

Service Workers 替换了 Manifest v3 Google Chrome Extensions 中的背景页面,我正在尝试将一个用于我的扩展。 文档说应该避免使用计时器( setTimeoutsetInterval ),因为当服务人员终止时计时器会被取消(这可能随时发生)。 与后台页面不同,service workers 不能持久化,并且总是会被终止。 该文档建议改用警报 API

我需要能够在 Manifest v3 service worker 中定期运行 function,但警报不适合我的用例,因为它们很慢。 允许的最短警报持续时间是 1 分钟,但我想以更短的间隔运行 function——一秒或几秒。

根据这个 Stack Overflow 答案,我尝试使用event.waitUntil让服务工作者保持活动状态。 这是我尝试通过重复waitUntil调用模仿 1 秒setInterval的解决方案:

var e;

function doThisEachSecond(resolver) {

    console.log('running function')

    // … CODE …

    e.waitUntil(new Promise(resolve => setTimeout(() => {doThisEachSecond(resolve);}, 1000)));
    resolver();
}

self.onactivate = event => {

    event.waitUntil(new Promise(resolve => {
        e = event;
        doThisEachSecond(resolve);
    }));

    console.log('activated');
};

它有很大的问题:

由于event.waitUntil使事件调度程序等待,因此当我的盗版setInterval运行时,这些事件不会触发:

chrome.tabs.onUpdated.addListener(…);
chrome.tabs.onReplaced.addListener(…);
chrome.runtime.onMessage.addListener(…);

而且我发现如果 service worker 运行一段时间(比如几分钟), doThisEverySecond最终会停止被调用。 发生这种情况时,在waitUntil期间排队的事件会立即全部触发。

看来我的方法不是通往 go 的方法。

您如何在 Chrome Extension Manifest V3 Background Service Worker 中每秒调用 function?

真的很抱歉,但这是不可能的。

既然我们已经得到了官方的回应:我没有适合你的好解决方案,但也许一个 hacky 的解决方案会奏效?

我知道您可以在 chrome 中创建一个命名警报,并让onAlarm调用所需的 function。我查看了文档,您可以创建的命名警报的数量似乎没有限制; 也许您可以创建 59 个chrome.alarm ,每个偏移量为 1000 毫秒?

哦等等,你不能在 service worker 中使用setTimeout 没关系,我会强制超时来设置它。

function asyncDelay(msToDelay) {
  return new Promise((success, failure) => {
      var completionTime = new Date().getTime() + msToDelay
      while (true) {
        if (new Date().getTime() >= completionTime){
          success()
          break
        }
      }
      failure()
  })
}

好的,所以现在我需要设置 60 个定时器,这样它们都会依次触发 1 秒。 不要忘记在设置时调用您的tick() function,否则它不会立即开始运行。

async function run() {
  for(let i = 0; i < 60; i++) {
    tick()
    await asyncDelay(1000)
    chrome.alarms.create(`recurring-polling-thread-${i}`, { periodInMinutes:1 })
  }
}

然后我们只需要在每次闹钟结束时触发滴答声。

chrome.alarms.onAlarm.addListener(() => {
  tick()
})

勾选 function 中的某种行为以确认它正在工作......

async function tick() {
  console.log(new Date().getTime())
}

多田! 现在每 1000 毫秒调用一次tick()

啊废话。

background.js:1 1647382803613
background.js:1 1647382804613
background.js:1 1647382805613
(8) background.js:1 1647382806614
(13) background.js:1 1647382806615
background.js:1 1647382807617
background.js:1 1647382808627
background.js:1 1647382809642

好吧,它有点管用,但一些警报同时响起。 查看 文档表明不遵守 1 秒的粒度:

为了减少用户机器上的负载,Chrome 将警报限制为最多每 1 分钟一次,但可能会延迟任意多的时间 也就是说,将 delayInMinutes 或 periodInMinutes 设置为小于 1 将不会被接受并会引起警告。 when 可以设置为在“现在”之后不到 1 分钟而不发出警告,但实际上不会导致至少 1 分钟的警报触发。

在我的本地测试中,我一直在运行这个 service worker 大约 10 分钟,它不会休眠,而且它几乎每秒都在滴答作响。 它并不完美,但我认为这足以提交。

代码在这里: https://github.com/EyeOfMidas/second-tick-extension

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM