简介:
由于JavaScript采用的是单线程模型,任务只能在一个线程上依次执行,每次只能做一件事情。随着计算机的计算能力的提升,多核CPU的出现,这样的单线程模式显然是不便的,无法充分发挥计算机的计算能力。
而Web Worker的作用,就是为JavaScript创建多线程的运行环境,允许主线程创建worker线程,将任务分配给后者来执行。主线程在执行任务的同时,worker线程在后台运行,互不干扰。
在worker线程执行完任务之后,将计算的结果返回给主线程,主线程拿到结果后进行剩下的一系列操作。
这样做的好处是,在进行计算密集型工作时,不占用主线程资源,worker线程进行计算,不会导致主线程被阻塞或拖慢。
web worker是HTML5提出的概念,分为两种类型——共享线程和专用线程。其中,专用线程只能被创建它的脚本所使用的,而共享线程则能够在不同脚本中使用。
用途:
web worker主要是用来进行计算密集型工作的,当脚本需要进行大量计算而阻塞主线程执行,从而影响用户体验的话,那么可以考虑将这些大量的计算放在worker中执行。
如:1.懒加载
2.图像处理
3.canvas图形绘制
4.数字运算、大数据处理等……
需要注意的地方:
1.受同源策略限制
2.无法在worker线程中获取到DOM节点
3.采用不同上下文,也就是说在worker线程中,无法获取到主线程的window对象
兼容性:
上图!

创建线程:
注意:受同源策略的影响,本地调试的时候需要起本地服务,file路径的脚本会被防掉,所以要在本地创建脚本,采用Blob的方式 传送门:developer.mozilla.org/zh-CN/docs/…
专用线程用Worker创建,接收两个参数,一个是创建线程执行的脚本文件的路径,另一个是可选的配置参数,可以指定type、credentials、name三个属性。

这样我们就成功创建了一个worker线程,那么线程之间的通讯也很重要,不然主线程也无法获取到worker线程的工作成果。
数据传递:
在主线程和worker线程都通过postMessage()来发送消息,通过onmessage来获取消息。这里需要注意的是,通过postMessage发送的数据并不是共享的 而是复制的。Error和Function对象不能够被正确复制,如果你尝试这么做的话,会被浏览器跑出一个Error,就像下面这样:


并且postMessage一次只能发送一个对象,若需要发送多条数据的话,可以放在一个数组里面。
下面我们来看一下onmessage接收到数据格式:

通过e.data就可以获取到我们想要得到的数据了。
加载脚本:
如果想在worker脚本中加载外部脚本的话,可以使用importScript()方法,importScript可以接收多个参数,为想要加载脚本的路径。
关闭worker:
在主页面调用terminate()方法可以主动关闭worker,或者在worker进程中可以调用自己的close()方法来主动杀死自己。
由于worker在执行完自己的工作后,还会一直保持连接状态,所以一定要记得主动关闭worker
实践一下:
我们来看一个demo,这里我们进行了一个9999999999次循环累加的计算,来看一下使用与不适用webworker的区别:



这是一段正常执行的js代码,可以看到,页面在一进来的时候一直在执行循环,页面变为挂起状态,并且阻塞了下面所有脚本的执行,由于这个循环计算,导致下面的代码无法执行,而且从页面打印的几个时间戳也可以很明显的看出来渲染和执行时间。整个执行过程长达149509毫秒,也就意味着用户需要等待149509的白屏
下面是使用web worker的效果:
可以看到,页面加载并没有被阻塞,主线程的代码正常执行,元素正常生成并插入,计算的过程好似并不存在。worker线程执行完毕后,将计算结果推给主线程,降低了主线程的运行压力,并且提升了用户体验。

