我可以将本地状态存储在 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 中的时间戳)应该是在它睡觉的时候触发的。
我正在使用 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 中的时间戳)应该是在它睡觉的时候触发的。