一、Web Worker的起因:
众所周知,在HTML5推出之前的 JavaScript 的运行都是以单线程的方式工作的,虽然有多种方式实现了对多线程的模拟
(例如:JavaScript 中的 setinterval 方法,setTimeout 方法等),但是在本质上程序的运行仍然是由 JavaScript 引擎以单线
程调度的方式进行的。单线程的不足就是效率低下。HTML5 中引入工作线程使得浏览器端的 JavaScript 引擎可以并发地执行
JavaScript 代码,实现了对浏览器端多线程编程的良好支持。从而提升处理效率。
引申:什么是线程,什么是进程。区别是什么?
进程我喜欢比喻成一个工厂,那么进程就是工厂中的员工。一个工厂可以有多名员工。也就是说一个进程里可以有多条线程。
在多线程中需要注意的是,进程中的各个线程是共享整个进程资源的,不过有些资源的容量有限,比如工厂的洗手间。这时候就
需要一种机制来进行维护。那就是利用“互斥锁”来完成。它的实现原理好比将进门的钥匙挂在门上,有线程进入这个资源就取走一
片钥匙,如果没有钥匙就无法进入房间,也就是说此资源共享容量已满。其中又会出现一些问题比如“死锁”,这里就不做延伸了。
想了解的朋友可以看:http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html
二、Web Worker的使用:
Web Worker的基本原理就是在当前javascript的主线程中,使用Worker类加载一个javascript文件来开辟一个新的线程,起到
互不阻塞执行的效果,并且提供主线程和新线程之间数据交换的接口:postMessage,onmessage。
具体实例:
①HTML页面:test.html
<!DOCTYPE HTML>②js页面:woker.js
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script type="text/javascript">
//WEB页主线程
var worker =new Worker("worker.js");
//创建一个Worker对象并向它传递将在新线程中执行的脚本的URL
worker.postMessage("hello world");
//向worker发送数据
worker.onmessage =function(evt){
//接收worker传过来的数据函数
console.log(evt.data);
//输出worker发送来的数据
}
</script>
</head>
<body></body>
</html>
//worker.js浏览器打开将在控制台输出
onmessage =function (evt){
var d = evt.data;
//通过evt.data获得发送来的数据
postMessage( d );
//将获取到的数据发送会主线程
}
hello world由上可以看出使用Web Worker主要分为以下几部分:
WEB主线程:
1.创建Worker,使用worker = new Worker( url ) 加载一个JS文件来创建一个worker,同时返回一个worker实例。
2.发送数据。通过worker.postMessage( data ) 方法来向worker发送数据。
3.接收数据。绑定worker.onmessage方法来接收worker发送过来的数据。
4.终止Worker。使用worker.terminate() 来终止一个worker的执行。(后面将使用)
Worker新线程(也就是上面的worker.js):
1.发送数据,通过postMessage( data ) 方法来向主线程发送数据。
2.接收数据,绑定onmessage方法来接收主线程发送过来的数据。
三、Web Worker能解决什么问题:
大家知道在数学上,斐波那契数列被以递归的方法定义:F0=0,F1=1,Fn=F(n-1)+F(n-2)(n>=2,n∈N*),
也是就是兔子生兔子的数列,而javascript的常用实现为:
<head>
<meta charset="UTF-8">
<meta name="Generator" content="EditPlus®">
<meta name="Author" content="">
<meta name="Keywords" content="">
<meta name="Description" content="">
<title>Document</title>
</head>
<body>
<script>
var fibonacci =function(n) {
return n <2? n : arguments.callee(n -1) + arguments.callee(n -2);
};
var timerStart = (new Date()).valueOf();
fibonacci(40);
var timerEnd = (new Date()).valueOf();
var timer = timerEnd - timerStart;
console.log('No Web Worker的时间为:'+timer);
</script>
</body>
</html>
最后运行的结果:
由于javascript是单线程执行,在求数列的过程中浏览器不能执行其它javascript脚本,UI渲染线程也会被挂起,从而
导致浏览器进入僵死状态。使用web worker将数列的计算过程放入一个新线程里去执行将避免这种情况的出现。
具体看例子:
①HTML页面:fibonacci.html页面:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>web worker fibonacci</title>
<script type="text/javascript">
onload =function(){
var worker =new Worker('worker.js');
worker.addEventListener('message', function(event) {
var timer2 = (new Date()).valueOf();
console.log( 'Web Worker用时:'+ ( timer2 - timer ) );
}, false);
var timer = (new Date()).valueOf();
worker.postMessage(40);
}
</script>
</head>
<body>
</body>
</html>
②js页面worker.js:
var fibonacci =function(n) {
return n <2? n : arguments.callee(n -1) + arguments.callee(n -2);
};
self.onmessage =function(event) {
postMessage(fibonacci(event.data));
}
最后结果如下:
对比发现worker的效率要高,这个也例子说明在worker中执行的fibonacci数列的计算并不会影响到主线程的代码执行
,完全在自己独立的线程中计算,只是在计算完成之后将结果发回主线程。利用web worker我们可以在前端执行一些复杂
的大量运算而不会影响页面的展示,并且不会弹出恶心的脚本正忙提示。
四、总结:
web worker有优点也有缺陷:
优势:
(1).可以加载一个JS进行大量的复杂计算而不挂起主进程,并通过postMessage,onmessage进行通信
(2).可以在worker中通过importScripts(url)加载另外的脚本文件
(3).可以使用 setTimeout(), clearTimeout(), setInterval(), and clearInterval()
(4).可以使用XMLHttpRequest来发送请求
(5).可以访问navigator的部分属性
局限性:
(1).不能跨域加载JS
(2).worker内代码不能访问DOM
(3).各个浏览器对Worker的实现不大一致,例如FF里允许worker中创建新的worker,而Chrome中就不行
(4).不是每个浏览器都支持这个新特性