了解web Worker实现多线程工作

分类:技术最近更新:2026-04-15浏览:1382

了解web Worker实现多线程工作

Web Worker 使用指南

概述

JS 是单线程的,也就是任务得一件件的按照顺序处理,前面的任务没有处理完成,后面的只能等着。但是随着科技的发展,现在的计算机都是多核的 CPU,单线程无法发挥计算机的能力。

Web Worker 的作用就是在 JS 主线程上创建一个辅助线程(Worker 线程),将一些任务分配给 Worker 线程运行。两个线程互不干扰,也能相互通信。用户在主线程上进行 UI 交互时,不会卡顿和阻塞。Worker 线程也不会因为主线程交互而被打断。这个和之前的 Service Worker 很类似。

注意,Worker 线程比较耗费资源,不应该过度使用,任务完成后要关闭。同时,Web Worker 有以下几个使用注意点:

  • 同源限制,执行 Worker 线程的脚本文件必须和主线程在一个 host 下
  • DOM 限制,Worker 线程不能操作 documentwindowparent 等对象,但可以操作 navigatorlocation 对象
  • 脚本限制,Worker 线程不能执行 alert()confirm() 方法,但可以使用 XMLHttpRequest 对象发出 AJAX 请求
  • 引用路径,Worker 线程引用文件时,必须是同源下的相对或者绝对路径
  • 上下文环境,Worker 线程和主线程不在同一个上下文环境,他们之间通过 xx.postMessage 相互通信
  • 通信数据独立,主线程和 Worker 线程传递的数据都是独立的,通信的数据都是先转字符串再还原的过程,所以不用担心对象深拷贝的问题

用法

主线程

1、在主线程上新建 worker 线程
javascript
var worker = new Worker('./work.js');

构造函数 Worker 引用的脚本文件 work.js 就是 Worker 线程的执行任务。如果构造函数 Worker 引用的参数路径不对,Worker 会默认失败,Worker 线程将不执行。

2、主线程给 Woker 线程发消息
javascript
worker.postMessage('Hello World'); worker.postMessage({method: 'echo', args: ['Work']});

主线程通过实例对象 workerpostMessage 向 Worker 发消息。postMessage 的参数可以是任意类型。

3、主线程监听 Woker 线程发消息
javascript
worker.onmessage = function (event) { console.log('Received message ' + event.data); doSomething(); } function doSomething() { // 执行任务 worker.postMessage('Work done!'); }

主线程通过调用实例 onmessage 方法监听 Worker 线程发来的消息(event.data)。

4、主线程关闭 Woker 线程
javascript
worker.terminate();

Worker 线程

1、Worker 线程监听主线程消息
javascript
self.addEventListener('message', function (e) { self.postMessage('You said: ' + e.data); }, false);

self 代表 Worker 线程的全局对象,等同下面两种写法:

javascript
// 写法一 this.addEventListener('message', function (e) { this.postMessage('You said: ' + e.data); }, false); // 写法二 addEventListener('message', function (e) { postMessage('You said: ' + e.data); }, false);
2、Worker 线程给主线程发送消息
javascript
self.addEventListener('message', function (e) { var data = e.data; switch (data.cmd) { case 'start': self.postMessage('WORKER STARTED: ' + data.msg); break; case 'stop': self.postMessage('WORKER STOPPED: ' + data.msg); self.close(); // Terminates the worker. break; default: self.postMessage('Unknown command: ' + data.msg); }; }, false);

和主线程方法一样,通过调用 Worker 线程的 postMessage 向主线程发送消息,参数就是发送的数据。

3、Worker 线程关闭自身
javascript
self.close();

拓展

1、可以在同一个文件里编写主线程和 worker 线程

html
<script type="text/js-worker"> // worker线程的脚本 addEventListener('message', function () { postMessage('some message'); }, false); </script> <script> // 主线程脚本 var blob = new Blob([document.querySelector('script[type="text/js-worker"]').textContent]); var url = window.URL.createObjectURL(blob); var worker = new Worker(url); worker.onmessage = function (e) { // e.data === 'some message' }; </script>

上面代码中,先将嵌入网页的脚本代码,转成一个二进制对象,然后为这个二进制对象生成 URL,再让 Worker 加载这个 URL。这样就做到了,主线程和 Worker 的代码都在同一个网页上面。


API

Worker()

javascript
var myWorker = new Worker(jsUrl, options);

主线程全局对象提供了 Worker 构造函数,它接收两个参数,第一个参数是脚本文件的同源网址,该参数必须的,否则会报错;第二个参数是可选的配置对象,它的主要作用是指定 Worker 线程的名称,用来区分多个 Worker 线程。

// 主线程

javascript
var myWorker = new Worker('worker.js', { name : 'myWorker' });

// Worker 线程

javascript
self.name // myWorker

Worker() 创建的实例对象,提供了以下属性和方法:

  • Worker.onerror:指定 error 事件的监听函数
  • Worker.onmessage:指定 message 事件的监听函数,发送过来的数据在 Event.data 属性中
  • Worker.onmessageerror:指定 messageerror 事件的监听函数。发送的数据无法序列化成字符串时,会触发这个事件
  • Worker.postMessage():向 Worker 线程发送消息
  • Worker.terminate():立即终止 Worker 线程

Web Worker 有自己的全局对象,不是主线程的 window,而是一个专门为 Worker 定制的全局对象。因此定义在 window 上面的对象和方法不是全部都可以使用。

Worker 线程有一些自己的全局属性和方法:

  • self.name:Worker 的名字。该属性只读,由构造函数指定
  • self.onmessage:指定 message 事件的监听函数
  • self.onmessageerror:指定 messageerror 事件的监听函数。发送的数据无法序列化成字符串时,会触发这个事件
  • self.close():关闭 Worker 线程
  • self.postMessage():向产生这个 Worker 线程发送消息
  • self.importScripts():加载 JS 脚本

兼容性

Dingtalk_20201007104922.jpg