# Web Worker 简单实例应用

> 前端页面开发过程中或多或少会使用setInterval()与setTimeout()方法，这两天准备用它们做个简单的页面检测，谁料出现了问题...

Author: DeathGhost
Published: 2023-09-04 19:43:06
Category: javascript
Canonical: https://www.deathghost.cn/article/javascript/114
Keywords: Web API, Web Worker, window.Worker, setInterval(), clearInterval(), setTimeout(), clearTimeout(), 页面卡死, 无响应

最近想做个简单前端页面检测功能，设置一个毫秒数（30分钟或1个小时），实时检测，如果当前时间与初始化时间差大于所设置的时间，页面自动跳转至其他指定页面。

第一时间想到的就是setInterval()与setTimeout()方法，初始化刚开始还表现还挺好，可走着走着就不对劲了😂，对其执行了clearInterval()与clearTimeout()也无济于事，用setTimeout()模拟setInterval()方法也不对，其症状二次触发时间加快，页面元素触发逐渐卡顿（点击相应慢），直至整个页面卡死，最后只能强制关闭浏览器。

以前偶尔也会用到那两个方法，也没遇到这种情况。🤨

不纠结了，也看到有人说试试Web Worker，那就最后一试了，同时先大概了解下Web Worker ...

![Web Worker 简单实例应用 - setInterval()](https://www.deathghost.cn/public/upload/article/2023/09/04/1693833198583291.jpg)

Web Worker 简单实例应用 - setInterval()

>
Web Worker 为 Web 内容在后台线程中运行脚本提供了一种简单的方法。线程可以执行任务而不干扰用户界面。

在 worker 内，不能直接操作 DOM 节点，也不能使用 window 对象的默认方法和属性。但是你可以使用大量 window 对象之下的东西，包括 WebSockets，以及 IndexedDB 等数据存储机制。

可使用函数

atob()
btoa()
clearInterval()
clearTimeout()
setInterval()
setTimeout()
window.requestAnimationFrame
window.cancelAnimationFrame
// ...

## 浏览器特性检测

window.Worker

## 生成一个 worker

const myWorker = new Worker("worker.js");

## 终止 worker

myWorker.terminate();
暂时够用，更多可参考：[https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API/Using_web_workers](https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API/Using_web_workers)

我项目框架是Angular，所以就按官方引导将其配置：

[https://angular.io/guide/web-worker](https://angular.io/guide/web-worker)

## 添加一个 Web Worker

ng generate web-worker
会自动新增tsconfig.worker.json文件，同时更新相应文件。

自己定义一个文件名，最后生成一个文件

/// <reference lib="webworker" />
addEventListener('message', ({ data }) => {
  const response = `worker response to ${data}`;
  postMessage(response);
});
然后在对应组件中引用

if (typeof Worker !== 'undefined') {
  // Create a new
  const worker = new Worker(new URL('./app.worker', import.meta.url));
  worker.onmessage = ({ data }) => {
    console.log(`page got message: ${data}`);
  };
  worker.postMessage('hello');
} else {
  // Web workers are not supported in this environment.
  // You should add a fallback so that your program still executes correctly.
}
以上也是官方文档中的例子。

最后，要注意的就是若更新所创建的worker文件(e.g. timer.worker.ts)时，需要重新启动项目，方可生效，否则不生效或找不到文件。

我还是在里面放一个setInterval()方法，让其根据时间间隔执行🤣。

// timer.worker.ts
const timeout: number = 1 * 60 * 60 * 1000;
let startTime = new Date().getTime();
let timerId = null;
设定一个时间，定义一个初始化开始时间。

timerId = setInterval(() => {
 check();
}, 1000);

function check() {
  if ((new Date().getTime() - startTime) > timeout) {
    postMessage(0);
  } else {
    postMessage(1);
  }
}

这里使用onmessage与postMessage接收与发送。如示例，超时发送0。这样就可以在组件中接收到此标记，进行其他操作。

通过监听光标"mouseover"，对其重置开始时间。

重置前记得先clearInterval(timerId);

this.root.addEventListener('mouseover', () => {
  const startTime = new Date().getTime();
  this.timerWorker.postMessage(startTime);
});

this.timerWorker.onmessage = async ({ data }) => {
  if (data === 0) {
    this.timerWorker.terminate();
    // ... 0 为超时，下面执行其他...
  }
}

大概就是这样子，测试了一会，感觉没问题，暂时就这样。

## Related

- Previous: [取消页面再次加载后的滚动位置](https://www.deathghost.cn/article/javascript/109)
- Next: [JS原生的深拷贝API structuredClone()](https://www.deathghost.cn/article/javascript/120)
