js多线程运行之web worker
众所周知,Js是单线程运行的,也就是运行完前一个函数之后,才能运行后一个函数。犹如单行道的车辆,其实这是js的一个短板,同时也导致了运行阻塞。虽然有时候我们可以通过定时器来并向执行代码,但这并不能真正解决问题。
在html5中有一个名为Web worker的api,它的产生就犹如人们发明了立交桥,使得js支持多线程运行。假设当前页面的代码为主线程,而创建Web worker则是为主线程开辟了另外一个新的子线程,因为是并行运行的,所以这个子线程不会阻塞主线程的执行。
Web worker是运行在后台的js,可以让web应用程序具备后台处理能力,即我们可以把一些非常复杂的运算、或一些很耗性能的js代码交给Web worker这个子线程来处理,然后再将得到的结果返回到主线程中,从而加快了页面的响应,但是正因为它是后台运行的js,所有它不能读取dom对象,但可以执行setInterval、setTimeout以及ajax请求。
相关用法
使用之前浏览器的兼容处理,然后需要新建Worker方法,这个方法的参数是后台js文件:
if (window.Worker) { |
那么问题来了,如何将主线程的数据处理任务交给子线程呢?也就是说它们之间如何通信?Web worker提供了postMessage函数和 onmessage事件,postMessage可以接收一个字符串或者json对象作为它的参数,在主线程中据说是开启webWorker,来看如下代码:
主线程(主页面):
webWorker.postMessage(str); |
子线程(web-worker.js):
self.addEventListener("message",function(e){ |
这里的self就是子线程,它通过使用onmessage事件监听变化,使用postMessage将计算的结果返回到主线程。如果你不想把数据处理的函数放在Web worker.js中,你也可以将其单独存为一个js文件,然后再在Web worker引入这个js文件,它也支持引入多个js文件,运行效果是一致。如下:
importScripts("fn1.js","fn2.js"); |
正如前面所说,计算结果返回到主线程后,那么如何接收它呢?我们同样可以通过在web Worker上绑定onmessage事件,得到计算结果即 e.data :
webWorker.addEventListener("message",function(e){ |
当程序运行结束后,我们需要关闭web worker,而关闭子线程主要可以通过以下两种方式;
在主线程关闭web worker:
webWorker.terminate(); |
或者在子线程关闭web worker:
self.close(); |
一些限制
子线程加载的js文件,必须与主线程在同一个域。也就是Web worker不能引入跨域的js文件。
因为Web worker是运行在后台的js程序,所以它不能像正常的js一样可以进行变量和函数的读取,也不能对dom进行操作。
最后Web worker必须是在服务器环境下运行。
最后还是来看一个列子:正常情况与使用web worker 生成30000个div所需时间,页面中显示了运行前后时间差,你也可以F12打开控制台查看更精确的运行时间。