Web Workers

2021-08-08 15:07:22 Javascript 大约 2 分钟

web worker 是运行在后台的 JavaScript,独立于其他脚本,不会影响页面的性能。当在 HTML 页面中执行脚本时,页面的状态是不可响应的,直到脚本已完成。您可以继续做任何愿意做的事情:点击、选取内容等等,而此时 web worker 在后台运行。

# web worker是什么

web worker 是运行在后台的 JavaScript。

  • 一个Web API 提供了一个js可以运行的环境。
  • web应用程序可以在独立于主线程的后台线程中,运行一个脚本操作。

# 解决的痛点是什么

js执行复杂运算时候阻塞了页面渲染;

# web worker限制

  • 与主线程脚本同源;
  • 与主线程的上下文不同;
    • 无法操作DOM;
    • 不能执行alert;
  • 不能读取本地文件;

# 执行过程

image-20210808145629319

如上图所示:主线程有一个postMessage方法用于发送消息,worker线程有onMessage方法用于监听消息,同时worker线程有一个postMessage方法,用于向主线程说明消息已经收到,然后主线程接收到结果就可以做自己的逻辑了。

# 外部引用web worker文件

创建 web worker 文件:

// worker.js`:
// 检测浏览器是否支持Worker:
if (typeof(Worker) !== 'undefined') {
    function fibonacci(n) {
        if (n === 1 || n === 2) {
            return 1;
        }
        return fibonacci(n-2) + fibonacci(n-1);
    }
    // 发送消息
    postMessage(fibonacci(40));
    
    // 监听worker线程传过来的消息
    onmessage = function(e) {
        console.log(e, 'worker');
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

创建 Web Worker 对象: 检测是否存在 worker,如果不存在,创建一个新的 web worker 对象,然后运行worker.js 中的代码

let worker;
if (typeof(worker) === 'undefined') {
    // 创建worker
    worker = new Worker('./worker.js');

    // // 监听主线程传过来的消息
    worker.onmessage = function (e) {
        console.log('worker通知的message', e);
        worker.postMessage('message收到了');
    }
}
1
2
3
4
5
6
7
8
9
10
11

运行:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body></body>
<script src="./webworker.js"></script>
</html>
1
2
3
4
5
6
7
8
9
10
11

fibonacci(40)运行的结果在 onmessage事件对象的 data 中;

注意

由于 web worker 位于外部文件中,它们无法访问下列 JavaScript 对象:

  • window 对象
  • document 对象
  • parent 对象

# 嵌入式worker

<!DOCTYPE html>
<html lang="en">

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

<script id="worker" type="javascript/worker">
  function fibonacci(n) {
      if (n === 1 || n === 2) {
          return 1;
      }
      return fibonacci(n-2) + fibonacci(n-1);
  }
  postMessage(fibonacci(40));
</script>

<script>
  // 读取script标签中的代码字符串;
  const workerScript = document.querySelector('#worker').textContent;
  // 转化为blob
  const blob = new Blob([workerScript], { type: "text/javascript" });
  // 创建worker对象;
  const worker = new Worker(window.URL.createObjectURL(blob));
  // 监听消息通知
  worker.onmessage = function(e) {
    console.log('worker通知message', e);
  }
</script>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

script标签的type应该是:javascript/worker

# 使用场景

  • 复杂运算;
  • 渲染优化;
  • 流媒体数据处理;
  • 性能考虑,web workers主要用于更耗费 CPU 资源的任务。
上次编辑于: 2023年7月4日 09:36