Web Worker 的基本使用
Published on Jan 30, 2023, with 14 view(s) and 0 comment(s)
Ai 摘要:JavaScript的单线程模型限制了任务执行效率。Web Worker通过创建后台线程,允许主线程分配计算密集型任务,避免UI阻塞。Worker线程独立运行,通过消息与主线程通信,但不能操作DOM或执行alert等操作。示例展示了主线程被alert阻塞时Worker仍能运行。适用场景包括文本解析和复杂运算,但需注意同源限制、通信机制和资源消耗,使用后应及时关闭。

JavaScript 语言采用的是单线程模型,也就是说,所有任务只能在一个线程上完成,一次只能做一件事。前面的任务没做完,后面的任务只能等着。随着电脑计算能力的增强,尤其是多核 CPU 的出现,单线程带来很大的不便,无法充分发挥计算机的计算能力。

Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。在主线程运行的同时,Worker 线程在后台运行,两者互不干扰。等到 Worker 线程完成计算任务,再把结果返回给主线程。这样的好处是,一些计算密集型或高延迟的任务,被 Worker 线程负担了,主线程(通常负责 UI 交互)就会很流畅,不会被阻塞或拖慢。

Worker 线程一旦新建成功,就会始终运行,不会被主线程上的活动(比如用户点击按钮、提交表单)打断。这样有利于随时响应主线程的通信。但是,这也造成了 Worker 比较耗费资源,不应该过度使用,而且一旦使用完毕,就应该关闭。

案例:

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script src="index.js"></script>
</body>

</html>
// index.js
const worker = new Worker("work.js"); //创建一个子线程worker

// worker.onmessage = (e) => {  //onmessage()用于接收worker发出的message
//   console.log("接收到了来自子线程的消息", e);
// };

setInterval(() => {
  console.log("主线程打印过一秒");
}, 1000);

// worker.postMessage("给子线程")  //postMessage()用于给worker发出的message

setTimeout(() => {
  // alert,confirm等会阻塞线程
  alert("阻塞主线程");
}, 2000);
// work.js
onmessage = (e) => {
  console.log("接收到了", e);
};

setInterval(() => {
  console.log("子线程过了一秒");
}, 1000);

postMessage("helloWorld");

案例中index.js为主线程,每隔一秒会打印 ”主线程打印过一秒“,当到了第二秒时会弹出 ”阻塞主线程“,不会继续执行setinterval里面的打印。 但是如果又创建一个子线程worker,work.js中setInterval正常打印。可见alert只会阻塞主线程上的打印,不会阻塞子线程上的打印。

实际运用场景:

  • 解析文本:例如在博客中需要将markdown语法转成html

  • 复杂的运算

注意点:

  • 同源限制:分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。

  • DOM限制:Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也无法使用document、window、parent这些对象。

  • 通讯联系:Worker 线程和主线程不在同一个上下文环境,它们不能直接通信,必须通过消息完成。

  • 文件限制:Worker 线程无法读取本地文件,即不能打开本机的文件系统(file://),它所加载的脚本,必须来自网络。

- 脚本限制:Worker 线程不能执行alert()方法和confirm()方法。

参考Web Worker 使用教程