一些背景原因
在【异步发展史,这次一定会!】中,因为js引擎是单线程的,所以我们需要异步编程,需要将耗时的操作异步处理。但是当这些执行异步任务时,它们先被放入浏览器的事件任务队列中去,等到执行栈空闲时才会按照队列先进先出的原则被一一执行,但终究还是单线程。若是复杂耗时的任务仍然会耗费较大的时间。
为了能使js引擎多线程,webworker应运而生,当然,js本身仍然是单线程,但是js运行的环境浏览器为其提供多线程。
WebWorker是什么❓
通过使用Web Workers,Web应用程序可以在独立于主线程的后台线程中,运行一个脚本操作。这样做的好处是可以在独立线程中执行费时的处理任务,从而允许主线程(通常是UI线程)不会因此被阻塞放慢。
好处:
-
Worker 线程新建后,就会长时间运行
-
不会被主线程上的活动(比如用户点击按钮、提交表单)打断
-
有利于随时响应主线程的通信,并同时保证页面对用户的及时响应。
劣势:
Worker 比较耗费资源,不应该过度使用,使用完毕,请立即关闭。
一些大坑:
1. 不能跨域
分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。
2. DOM 限制
Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也无法使用document、window、parent这些对象。但是,Worker 线程可以navigator对象和location对象。
3.通信联系
Worker 线程和主线程不在同一个上下文环境,它们不能直接通信,必须通过消息完成。
4.脚本限制
Worker 线程不能执行alert()方法和confirm()方法,但可以使用 XMLHttpRequest 对象发出 AJAX 请求。
5.文件限制
Worker 线程无法读取本地文件,即不能打开本机的文件系统(file://),它所加载的脚本,必须来自网络。
😈WebWorker怎么用
基本用法
1.新建一个Worker线程
//形如const myWorker = new Worker(aURL, options); aURL:js文件名 [options]一些属性
let myWorker = new Worker("worker.js");
//在chrome中不允许读取本地文件,所以最好起一个本地服务器读取或者是读取同源网络文件
2.线程通信
onmessage: 监听事件
postmessage: 传送事件
主线程文件
//当触发耗时事件时
first.onchange = function() {
myWorker.postMessage([first.value,second.value]);
console.log('Message posted to worker');
}
second.onchange = function() {
myWorker.postMessage([first.value,second.value]);
console.log('Message posted to worker');
}
worker.js
self.onmessage = function(event){
console.log('Worker recieved message');
};
3.结束时关闭
主线程文件
myWorker.terminate();
子线程文件
self.close();
4.错误处理
主线程可以监听 Worker 是否发生错误。如果发生错误,Worker 会触发主线程的error事件
//方一:
myWorker.onerror(function (event) {
});
//方二:
myWorker.addEventListener('error', function (event) {
});
5.加载其他文件
Worker 内部如果要加载其他脚本,有一个专门的方法importScripts()
importScripts(); /* imports nothing */
importScripts('foo.js'); /* imports just "foo.js" */
importScripts('foo.js', 'bar.js'); /* imports two scripts */
importScripts('//example.com/hello.js'); /* You can import scripts from other origins */
6.线程间的数据通信
主线程与worker之间的通信是一种值拷贝的过程,即是传值而不是传址。实际上是先将数据JSON.stringify之后再JSON.parse。以这种拷贝的方式会造成性能问题。比如,主线程向 Worker 发送一个 500MB 文件,默认情况下浏览器会生成一个原文件的拷贝。为了解决这个问题,JavaScript 允许主线程把二进制数据直接转移给子线程,但是一旦转移,主线程就无法再使用这些二进制数据了,这是为了防止出现多个线程同时修改数据的麻烦局面。这种转移数据的方法,叫做Transferable Objects。这使得主线程可以快速把数据交给 Worker,对于影像处理、声音处理、3D 运算等就非常方便了,不会产生性能负担。
var transfer = new ArrayBuffer(1);
worker.postMessage(transfer, [transfer]);
WebWorker的使用场合
1. 庞大复杂数学计算
2. 图像处理
通过使用从<canvas>或者<video>元素中获取的数据,可以把图像分割成几个不同的区域并且把它们推送给并行的不同Workers来做计算
3. 大量数据的请求
4. 背景数据分析
由于在使用Web Worker的时候,我们有更多潜在的CPU可用时间,我们现在可以考虑一下JavaScript中的新应用场景。例如,我们可以想像在不影响UI体验的情况下实时处理用户输入。利用这样一种可能,我们可以想像一个像Word(Office Web Apps 套装)一样的应用:当用户打字时后台在词典中进行查找,帮助用户自动纠错等等
🌰试一试
git 地址
注意:要用http-server形式开启才能打开文件
参考
官方文档
阮一峰老师的博客
聊聊Webworker ⬅️这位写的超棒 还有在线demo 建议全文细读