Web Worker
Jul 27, 2022 ·
5 Min Read
一、概述
众所周知,JavaScript 语言采用的是单线程模型,也就是,所有任务在一个线程上完成,一次只能做一件事。如果前面的任务没有完成,则阻塞后面的任务。极大浪费 CPU 的计算能力↘️。
避免阻塞有两种方法:
- 异步(这里不展开说)
- 多线程(其实也不算是避免阻塞,只是同时可以处理多个任务,减少阻塞的可能)
Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker线程,将一些任务分配给子线程运行,主线程和子线程互不干扰。
场景:比如在一些需要密集计算的任务,可以交给 子线程 执行,主线程继续负责 UI 交互,保证页面的流畅性。
注意
- 同源限制,即 Worker 线程的脚本文件必须与主线程 的脚本文件同源。
- 无法访问
DOM, Worker 线程 无法读取主线程所在网页的 DOM 对象,也就是没有document、window、parent,但有navigator对象和location对象。 - 通信限制,必须通过
postMessage()和 监听onmessage()来进行通信。 - 不能访问本地文件,即
file://。
二、基本使用
(1)创建 Worker 线程
通过调用 Worker() 构造函数,新建一个 Worker 线程
// 第一个参数必须是一个脚本文件,第二个参数可选,详情可看文档const worker = new Worker('myWork.js')(2)向 Worker 线程发送信息
// postMessage 可以发送任意类型的数据worker.postMessage('hello world!')worker.postMessage({ eventType: 'sayHi', message: 'hellp world!'})(3)主线程接收 Worker 线程信息
worker.onmessage = (event) => { // 通过事件对象的 data 属性获取 Worker 发送过来的信息 console.log('worker message:', event.data) // do something}(4)销毁 Worker 线程
// 建议 Worker 完成任务后,关闭 Worker 线程,避免浪费资源。// 注意:销毁或 Worker 线程主动关闭后,必须需要重新创建使用。worker.terminate()(5)Worker 线程接收主线程信息 和 向主线程发送信息
// 三种写法等价的,self 和 this 都代表子线程的全局对象,可以使用 addEventListener,也可以使用 onmessage。// Worker 线程也和主线程一样,使用 possMessage() 发送信息。
// 写法一addEventListener('message', e => { // do something postMessage('I am a Worker thread')}, false)
// 写法二this.addEventListener('message', e => { // do something this.postMessage('I am a Worker thread')}, false)
// 写法三self.addEventListener('message', e => { // do something self.postMessage('I am a Worker thread')}, false)(6)关闭自身 Worker 线程
// 在 Worker 线程使用。// 效果与 主线程调用 terminate() 一样,只是一个由主线程发起销毁 Worker 线程,而这里是 Worker 线程主动关闭。self.close()(7)Worker 加载脚本
importScripts('spript1.js'[, ...])
// 除此之外配合 webpack 使用,则可以使用 ES6 import 加载方法。主要方法
Worker.onerror:指定 error 事件的监听函数。Worker.onmessage:指定 message 事件的监听函数,发送过来的数据在Event.data属性中。Worker.onmessageerror:指定 messageerror 事件的监听函数。发送的数据无法序列化成字符串时,会触发这个事件。Worker.postMessage():向 Worker 线程发送消息。Worker.terminate():立即终止 Worker 线程。
三、webpack 或 vue 中使用
在 webpack 4.x 版本下 需要安装 work-loader 。
详细配置建议查看
work-loadergithub 的 README,webpack 官网下 loader 文档稍微有点旧了,新版的work-loader部分配置属性名更改或删除。
💡例:
// webpack{ module: { rules: [ { test: /\.worker\.js$/, use: { loader: 'worker-loader' } options: { inline: 'fallback', filename: '[name].[hash].js' } } ] }}
// vue cli// vue.config.jschainWebpack: (config) => { config.module .rule('worker') .test(/\.worker\.js$/) .use('worker-loader') .loader('worker-loader') .options({ inline: 'fallback', filename: '[name].[hash].js' }).end()
config.output.globalObject('this') // 注入全局变量 config.module.rule('js').exclude.add(/\.worker\.js$/) // 修改响应}💡使用:
// where you need itimport worker from 'myWorker.js'
const worker = new worker()worker.onmessage = function (event) { // Received message:I am the message from the thread console.log('Received message:' + event.data) worker.terminate()}worker.postMessage('hello world!')
// myWorker.jsaddEventListener('message', function(e) { // from main thread:hello world! console.log('from main thread:' + e.data) // do something
self.postMessage('I am the message from the thread')}, false)❗ 在 webpack 5.x 中,可以使用 web workers 来代替 work-loader。
const worker = new Worker(new URL('./myWorker.js', import.meta.url))// do something Last edited Feb 15