我们经常说 JavaScript 是单线程,是指相对于 JAVA 等语言,JavaScript 不具备并行任务处理的特性。JS 具有一个主线程,所有的任务需要排队进行处理。主线程在执行前面的任务时,会阻塞后面的任务。
随着计算机处理能力的提高,这种单线程模型无法充分发挥多核 CPU 计算机的计算能力。为了让 JS 也能够有多线程能力,诞生了 Web Worker 。
现在我们可以在主线程中创建 worker 线程,将一些计算密集型或高延迟的任务分配给 worker 线程运行。worker 线程与主线程并行运行,互不干扰,这就避免了单线程任务阻塞的情况。
Web Worker
基本用法
首先需要注意一些限制:
- 同源限制:创建 worker 线程的时候需要分配一个 JS 文件,该文件必须是同源的,且不能是本地文件;
- 环境隔离:worker 线程所在的上下文环境与主线程不一样,无法读取网页的 DOM 对象,全局对象不再是 window,可以通过 this 或 self 访问。
- 通信受限:主线程和 worker 线程不能直接通信,通过
postMessage
方法进行消息传递。
在主线程中,可以调用Worker来创建一个线程
let worker = new Worker('work.js') // 必须传递一个 url,受同源限制
主线程通过调用 postMessage
方法,向 worker 线程传递数据,数据类型不限:
worker.postMessage('Hello World');
worker.postMessage({a:1, b:2});
主线程通过监听 onmessage
事件,接收子线程传递的信息:
worker.onmessage = function(event) {
console.log(event.data); // data 就是 worker 传递的数据
}
woker 线程内同样通过监听 onmessage
事件,接收主线程传递的数据,通过 postMessage
传递数据:
self.addEventListener('message', function(event) {
console.log(event.data); // data 为传递的数据
// do something...
self.postMessage('get✔');
})
错误处理:
// 主线程
worker.onerror(function (event) {
console.log([
'ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message
].join(''));
});
// 子线程
self.onerror(function (event) {
console.log([
'ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message
].join(''));
});
在 woker 线程执行完毕之后,需要关闭线程,释放资源:
// 主线程
worker.terminate();
// 子线程
self.close();
总结
- 使用 worker 构造函数创建 worker 线程,需要传递一个同源脚本文件 URL;
- 使用
postMessage
、onmessage
方法事件进行消息传递;- 通过
onerror
事件处理异常,使用close
方法关闭线程;- worker 线程任务可以是 JS 脚本文件,也可以是内联脚本;