我可以将本地状态存储在 Web Worker 中吗

can I store local state in a web worker

我正在使用 VSCode 在 javascript 中学习 Web Worker。我的工作人员在其 onmessage 事件期间设置了一个间隔。理想情况下调用 start 只会创建间隔,如果它还没有 运行.

onmessage = (event: MessageEvent) => {
  let interval;

  switch (event.data.command){
    case "start":
      if (!interval){
        interval = setInterval(myFunction, 1000);
      }
      break;
    case "stop":
      if (interval){
        clearInterval(interval);
        interval = null;
      }
      break;
  }
}

问题是 interval 在函数的执行过程中被定义,所以我可以开始多个间隔,而它们中的任何一个都不知道彼此。

const worker = new Worker("myworker.ts");
worker.postmessage({command: "start"});
worker.postmessage({command: "start"});
worker.postmessage({command: "start"});

如果我像这样修改 web worker 代码以使用全局变量,那么根据 VSCode 其他 worker 文件将可以访问间隔变量:

let interval; // Error: `interval` is already defined in `anotherWorker.ts`

onmessage = () => {
  // ...
  if (!interval){
    interval = setInterval(myFunction, 1000);
  }

  // ...
  if (interval){
    clearInterval(interval);
    interval = null;
  }
}

即使每个 worker 都有自己的范围,如果我在 worker 中重复使用变量名,VSCode 也会继续抛出错误。

如何为 worker onmessage 函数创建本地状态?

您可以将 onmessage 处理程序包装在它自己的块中,并在那里声明您的 interval。这样,其他模块将看不到它,但它仍然会在不同的消息事件中持续存在。

{ // <- defines a new block
  let interval; // <- only for us, but still the same for all message events

  onmessage = () => {
    // ...
    if (!interval){
      interval = setInterval(myFunction, 1000);
    }

    // ...
    if (interval){
      clearInterval(interval);
      interval = null;
    }
  };
}

我最近 运行 在采用 @Kaiido 在服务工作者中的回答这样的方法时遇到了问题。浏览器可能会在他们认为合适的时候重启服务工作者(可能还有其他工作者?),因此您可能会丢失存储在工作者变量中的状态。

在我的例子中,我创建了一个 service worker 来 return 如果用户处于非活动状态,应用程序的所有实例都会进入登录页面。由于工作程序被浏览器重新启动并且失去了我设置的超时,这有时会失败。

如果你想在 service worker 重新启动时保持状态,你应该将状态存储在 IndexedDB and re-initialize any worker-localized state whenever it is reactivated

对于需要工作人员保持活动状态的超时和间隔之类的事情,您可能会强烈考虑将该功能移动到客户端应用程序中,在合理的情况下。否则,您可能会考虑以您可以容忍的最大 g运行ularity 定期发送保持活动消息,以确保它将在该间隔重新激活并有机会在超时时采取行动(通过存储在 IndexedDB 中的时间戳)应该是在它睡觉的时候触发的。