web worker实际使用
web worker的好处
相信大家都比较熟悉,比如:
- 为js创造多线程环境,一些 计算量大的 耗时的 任务,可以用web worker单独开线程去跑,不会影响到主线程的运行
- 这样主线程(ui交互渲染等)就不会被阻塞,页面流畅
实际如何使用呢?
首先要理解一个区别,主线程和子线程是分别独立,不要混在一起去理解
上一段代码,方便理解:
// 文件的目录结构:
├── index.html
└── poorWorker.js (穷人打工仔,worker,干活的人)
这是主线程:index.html
<script>
const worker = new Worker('./poorWorker.js');
worker.postMessage("我是主进程, 我是boss,我传给worker线程消息: 赶紧干活!!");
worker.onmessage = msg => {
console.log(msg)
console.log("我是主进程,我是boss,接收的子线程的数据:", msg.data);
worker.terminate(); // 关闭主线程
};
worker.onerror = e => {
console.log(e)
};
</script>
这是子线程:poorWorker.js
// importScripts('./hello2.js', 'http://xxx/a.js'); // 此处可以指出多脚本, 加载的脚本不支持跨域!!
// self 代表子线程自身,即子线程的全局对象。
// self可以换成this或不写,也可以实现执行。此处用self用于区分子线程worker
// 监听主线程传过来的信息
self.onmessage = e => {
console.log(e)
console.log('我是子线程, 我在工作, 我是worker, 我收到主线程传来的信息:', e.data)
// do something
}
// setTimeout非必须,此处模拟,worker干了个耗时的活,2s后告诉主线程(老板)活已经干完ok了。
setTimeout(() => {
// 发送信息给主线程
self.postMessage('我是子线程, 我在工作, 我是worker, 工作已经完成 ok')
closeSon()
}, 2000)
// 关闭worker线程
function closeSon () {
return self.close()
}
打印效果如下:
骚操作写法介绍(更推荐上面的写法)
正常情况,推荐上面的写法:把worker部分,单独分离成一个.js文件。
但强行把worker部分,不分离成.js,强行写在index.html内,也可以做到
这是 index.html
<script>
// 此处把上面的poorWorker.js放到data中
const data = `
// importScripts('./hello2.js', 'http://xxx/a.js'); // 此处可以指出多脚本, 加载的脚本不支持跨域!!
// self 代表子线程自身,即子线程的全局对象。
// self可以换成this或不写,也可以实现执行。此处用self用于区分子线程worker
// 监听主线程传过来的信息
self.onmessage = e => {
console.log(e)
console.log('我是子线程, 我在工作, 我是worker, 我收到主线程传来的信息:', e.data)
// do something
}
// setTimeout非必须,此处模拟,worker干了个耗时的活,2s后告诉主线程(老板)活已经干完ok了。
setTimeout(() => {
// 发送信息给主线程
self.postMessage('我是子线程, 我在工作, 我是worker, 工作已经完成 ok')
closeSon()
}, 2000)
// 关闭worker线程
function closeSon () {
return self.close()
}
`;
const blob = new Blob([data]); // 把poorWorker.js的内容转成二进制
const url = window.URL.createObjectURL(blob); // 把二进制转成一个本地链接
const worker = new Worker(url); // 利用了new Worker()只接受url的特点
// ... 后面的代码同上
worker.postMessage("我是主进程, 我是boss,我传给worker线程消息: 赶紧干活!!");
worker.onmessage = msg => {
console.log(msg)
console.log("我是主进程,我是boss,接收的子线程的数据:", msg.data);
worker.terminate(); // 关闭主线程
};
worker.onerror = e => {
console.log(e)
};
</script>
最后(断开)
Worker 线程一旦新建成功,就会始终运行,不会被主线程上的活动(比如用户点击按钮、提交表单)打断。这样有利于随时响应主线程的通信。
但是,这也造成了 Worker 比较耗费资源,不应该过度使用,而且一旦使用完毕,就应该关闭。
码字不易,点赞鼓励