web Worker使用笔记
# 一、前言
JavaScript 语言采用的是单线程模型
,也就是说,所有任务只能在一个线程上完成,一次只能做一件事。前面的任务没做完,后面的任务只能等着。
随着电脑计算能力的增强,尤其是多核 CPU 的出现,单线程带来很大的不便,无法充分发挥计算机的计算能力。
Web Worker
的作用,就是为 JavaScript 创造多线程环境。
Worker
线程在后台运行,两者互不干扰。Worker
线程完成计算任务,再把结果返回给主线程Worker
线程一旦新建成功,就会始终运行,这也造成了 Worker 比较耗费资源,不应该过度使用
,而且一旦使用完毕,就应该关闭
Web Worker
有以下几个使用注意点。
(1).同源限制
分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。
(2). DOM 限制
Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,
也无法使用document
、window
、parent
这些对象。但是,Worker
线程可以使用navigator
对象和location
对象
(3). 通信联系
Worker 线程和主线程不在同一个上下文环境,它们不能直接通信,必须通过消息完成。
(4). 脚本限制
Worker 线程不能执行alert()
方法和confirm()
方法,但可以使用 XMLHttpRequest
对象发出 AJAX
请求。
(5). 文件限制
Worker 线程无法读取本地文件,即不能打开本机的文件系统(file://),它所加载的脚本,必须来自网络。
# 二、基本用法
# 主线程
var worker = new Worker('work.js'); #新建线程
/**
* #主线程向 子线程worker发送消息
* @params string|Object|Array|Boolean|binary 等等
*/
worker.postMessage('Hello World');
接收子线程发回来的消息
worker.onmessage = function (event) {
console.log('Received message ' + event.data);
//to do something ...
}
错误处理
worker.onerror(function (event) {
console.log([
'ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message
].join(''));
});
关闭worker,使用完毕,为了节省系统资源,必须关闭 Worker。
worker.terminate();#主线程
worker.postMessage({cmd:'close'});# Worker 线程
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 子线程 work.js
# Worker 内部如果要加载其他脚本,可以使用importScripts(),如果无脚本文件加载删除即可
importScripts('script1.js', 'script2.js');
监听`主线程`传递过来的消息
this.addEventListener('message', function (e) {
var data = e.data;
switch (data.cmd) {
case 'close':
self.close(); // 关闭 worker.
default:
this.postMessage('You said: ' + e.data);
}, false);
2
3
4
5
6
7
8
9
10
11
12
13
更多详细内容,参考大佬链接 阮一峰 Web Worker使用教程
# 三、vue-worker
# 1、安装
npm i -S vue-worker
# 2、注册 main.js
import VueWorker from 'vue-worker'
Vue.use(VueWorker)
2
# 3、使用
1). run是一次性的,跑完这次,worker线程就会被关掉,适用只执行一次的大计算操作
export default {
data() {
return {
worker: null
}
},
mounted() {
/**
* 开启新的线程
* @params1 n=>{} = worker 中的addEventListener
* @params2 [2] = worker.postMessage
*/
this.worker = this.$worker.run(n => {
return n+10
}, [2])
.then(res =>{// worker中的wroker.onmessage
//do something
})
.catch(e => console.log(e))
},
destroyed() {
this.worker = null //关闭worker
},
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2). 持久化worker
export default {
data() {
return {
worker: null
}
},
created() {
//create 的内容适用Blob来创建一个可执行的二进制上下文
this.worker = this.$worker.create([
{
message: 'task1',
func(data) {
// do something
return data
},
},
{
message: 'task2',
func(id) {
//do something
return id
},
}
])
},
mounted(){
//只执行task1
this.worker.postMessage('task1', [data]).then(res => console.log(res))
//create的所有任务都执行
this.worker.postAll().then((data))=> {})
//执行`task1` `task2`
this.worker.postAll([{ message: 'task1', args: [{ name: 'li si' }] },{ message: 'task2', args: [{ name: 'zhang san' }] }]).then((data)=> {})
//不想要其中一个任务时 注销task1
this.worker.unregister('task1')
//追加 task3
this.worker.register({ message: 'task3', func: (data) => {return data} })
},
destroyed() {
this.worker = null //关闭worker
},
}
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
34
35
36
37
38
39
40
41
42
# 4、关闭worker 问题
插件的作者指出,你是没办法拿到worker原始实例的,所以也就无法调用worker.terminate()或者在worker线程内部执行self.close()来关闭worker。 create方法创建的不是worker实例,所以它内部有,但是没有暴露出来。所以插件没有关闭worker的方法,你直接把worker对象释放掉即可。 我翻阅了源码,发现它只在调用run方法时才使用close,执行完run之后worker会被close,但是如果你使用create创建的worker,是不会被close的它会一直存在,直到你关闭浏览器。
# 5、原理
web worker 通过worker对象创建的,传入javascript文件作为worker的执行脚本
vue-worker 通过Blob来创建一个可执行的二进制上下文,在通过这个上下文来调用我们传入的function,就好像在内存中虚拟了一个内容是我们传入的function的js文件一样