Web Worker
Web Worker提供了一个简单的方法使得 web 内容能够在后台运行脚本。一旦 worker 创建后,它可以向由它的创建者指定的事件监听函数传递消息,这样该 worker 生成的所有任务就都会接收到这些消息
worker 线程能够在不干扰 UI 的情况下执行任务。另外,它还能够使用 XMLHttpRequest (虽然 responseXML 与 channel 两个属性值始终是 null)来执行 I/O 操作。
生成 worker
创建一个新的 worker 十分简单。你所要做的就是调用 Worker() 构造函数,指定一个要在 worker 线程内运行的脚本的 URI,如果你希望能够收到 worker 的通知,可以将 worker 的 onmessage 属性设置成一个特定的事件处理函数。
var myWorker = new Worker("my_task.js"); myWorker.onmessage = function (oEvent) { console.log("Called back by the worker!\n"); };
或者,你也可以使用 addEventListener()
:
var myWorker = new Worker("my_task.js"); myWorker.addEventListener("message", function (oEvent) { console.log("Called back by the worker!\n"); }, false); myWorker.postMessage(""); // start the worker.
例子中的第一行创建了一个新的 worker 线程。第三行为 worker 设置了 message 事件的监听函数。当 worker 调用自己的 postMessage() 函数时就会调用这个事件处理函数。最后,第七行启动了 worker 线程。
传递数据
在主页面与 worker 之间传递的数据是通过拷贝,而不是共享来完成的。传递给 worker 的对象需要经过序列化,接下来在另一端还需要反序列化。页面与 worker 不会共享同一个实例,最终的结果就是在每次通信结束时生成了数据的一个副本。大部分浏览器使用结构化拷贝来实现该特性。
实例:创建一个子线程来计算求和
<!DOCTYPE html><html><head> <title>webWorkers 实例演示</title></head><body> 请输入要求和的数:<input type="text" id="num"><br> <button onclick="caculate()">计算</button> <script type="text/javascript"> //1.创建计算的子线程 var worker = new Worker("worker1.js"); function caculate(){ var num = parseInt(document.querySelector('#num').value,10); //2.将数据传递给子线程 worker.postMessage(num); } //3.从子线程接收处理结果并展示 worker.onmessage = function(event){ alert('总和为:'+ event.data); } </script></body></html>
onmessage = function(event){ var result =0, num = event.data; for(var i = 1; i < num ;i ++){ result += i; } //向主线程返回消息 postMessage(result); }
可以将比较耗时的处理交给一个后台线程,去处理,处理完之后将结果返回给主页面。
线程之间进行数据交互
线程间的数据交互是通过发送和接收消息来相互传递信息的,主线程首先创建Worker,通过Worker对象的postMessage方法,将数据传递给后台线程,而主程序通过onmessage 事件,或者自定义addEventListener
事件来监听后台返回后台线程处理的结果。同样,后台线程通过onmessage事件来接收主页面传递的数据,通过postMessage将处理结果返回给主页面。
实例:页面序随机产生100个数据,并将数据传递给后台线程过滤,将可以被3 整除的数据,返回给主页面,以动态表格的形式显示。
<!DOCTYPE html><html><head> <title>线程之间进行数据交互</title></head><body> <h2>线程之间进行数据交互</h2> <table id="table" style="color: #FFF;background-color: #ccc;"> </table></body> <script type="text/javascript"> var nums = new Array(100), intStr = ""; //1.处理非字符串数据 for(var i = 0; i<100; i++){ nums[i] = parseInt(Math.random()*100); intStr += nums[i] + ";"; } //2.创建新进程 var worker = new Worker("worker2.js"); //3.向子进程发送数据 worker.postMessage(intStr); //4.从子线程获取处理结果 worker.onmessage = function(event){ var row, col, tr, td, table = document.querySelector("#table"); var numArr = event.data.split(";"); for(var i = 0; i<numArr.length; i++){ row = parseInt(i/10); col = i%10; if (col == 0 ) { tr = document.createElement("tr"); tr.id = "tr" + row; table.appendChild(tr); }else{ tr = document.querySelector("#tr" + row); } td = document.createElement('td'); tr.appendChild(td); td.innerHTML = numArr[i]; td.width = "30"; } } </script></html>
onmessage = function(event){ var strNum = event.data; var numArr = strNum.split(";"); var returnNum = ""; for(var i =0; i<numArr.length; i++){ if (numArr[i]%3 ==0) { returnNum += numArr[i] + ";"; } } postMessage(returnNum); }
线程间的嵌套
线程中可以嵌套子线程,这样可以把一个较大的后台线程切分成几个子线程,每个子线程格子完成相对独立的工作。
还是使用上述的实例,构造一个单层子线程嵌套的例子。把之前主页面生成随机数的工作放到后台线程,然后在后台线程中构造一个子线程,来挑选出可以被3整除的数据。传递的数据采用JSON的数据格式。
<!DOCTYPE html><head><meta charset="UTF-8"><script type="text/javascript">var worker = new Worker("script.js"); worker.postMessage("");// 从线程中取得计算结果worker.onmessage = function(event) { if(event.data!="") { var j; //行号 var k; //列号 var tr; var td; var intArray=event.data.split(";"); var table=document.getElementById("table"); for(var i=0;i<intArray.length;i++) { j=parseInt(i/10,0); k=i%10; if(k==0) //该行不存在 { //添加行 tr=document.createElement("tr"); tr.id="tr"+j; table.appendChild(tr); } else //该行已存在 { //获取该行 tr=document.getElementById("tr"+j); } //添加列 td=document.createElement("td"); tr.appendChild(td); //设置该列内容 td.innerHTML=intArray[j*10+k]; //设置该列背景色 td.style.backgroundColor="blue"; //设置该列字体颜色 td.style.color="white"; //设置列宽 td.width="30"; } } };</script></head><body><h1>从随机生成的数字中抽取3的倍数并显示示例</h1><table id="table"></table></body>
script.js子线程代码
onmessage=function(event){ var intArray=new Array(100); //随机数组 //生成100个随机数 for(var i=0;i<100;i++) intArray[i]=parseInt(Math.random()*100); var worker; //创建子线程 worker=new Worker("worker2.js"); //把随