程序员人生 网站导航

html5 多线程处理webWorker

栏目:htmlcss时间:2016-06-14 09:13:46

Web Worker

Web Worker提供了1个简单的方法使得 web 内容能够在后台运行脚本。1旦 worker 创建后,它可以向由它的创建者指定的事件监听函数传递消息,这样该 worker 生成的所有任务就都会接收到这些消息

worker 线程能够在不干扰 UI 的情况下履行任务。另外,它还能够使用 XMLHttpRequest (虽然 responseXML 与 channel 两个属性值始终是 null)来履行 I/O 操作。

生成 worker

创建1个新的 worker 10分简单。你所要做的就是调用 Worker() 构造函数,指定1个要在 worker 线程内运行的脚本的 URI,如果你希望能够收到 worker 的通知,可以将 worker 的 onmessage 属性设置成1个特定的事件处理函数。

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.

例子中的第1行创建了1个新的 worker 线程。第3行动 worker 设置了 message 事件的监听函数。当 worker 调用自己的 postMessage() 函数时就会调用这个事件处理函数。最后,第7行启动了 worker 线程。

传递数据

在主页面与 worker 之间传递的数据是通过拷贝,而不是同享来完成的。传递给 worker 的对象需要经过序列化,接下来在另外一端还需要反序列化。页面与 worker 不会同享同1个实例,终究的结果就是在每次通讯结束时生成了数据的1个副本。大部份阅读器使用结构化拷贝来实现该特性。

实例:创建1个子线程来计算求和

<!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); }

可以将比较耗时的处理交给1个后台线程,去处理,处理完以后将结果返回给主页面。

这里写图片描述

线程之间进行数据交互

线程间的数据交互是通过发送和接收消息来相互传递信息的,主线程首先创建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); }

这里写图片描述

线程间的嵌套

线程中可以嵌套子线程,这样可以把1个较大的后台线程切分成几个子线程,每一个子线程格子完成相对独立的工作。

还是使用上述的实例,构造1个单层子线程嵌套的例子。把之前主页面生成随机数的工作放到后台线程,然后在后台线程中构造1个子线程,来挑选出可以被3整除的数据。传递的数据采取JSON的数据格式。

<!DOCTYPE html> <head> <meta charset="UTF⑻"> <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"); //把随机数组提交给子线程进行挑选工作 worker.postMessage(JSON.stringify(intArray)); worker.onmessage = function(event) { //把挑选结果返回主页面 postMessage(event.data); } }

worker2.js代码

onmessage = function(event) { //还原整数数组 var intArray= JSON.parse(event.data); var returnStr; returnStr=""; for(var i=0;i<intArray.length;i++) { //能否被3整除 if(parseInt(intArray[i])%3==0) { if(returnStr!="") returnStr+=";"; //将能被3整除的数字拼接成字符串 returnStr+=intArray[i]; } } //返回拼接字符串 postMessage(returnStr); //关闭子线程 close(); }

这里写图片描述

向子线程传递消息时,用worker.postMessage,向主页面提交数据时直接用postMessage.

多个子线程之间的数据交互

<!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 worker1 = new Worker("worker1.js"); worker1.postMessage(""); //从子线程获得处理结果 worker1.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>

worker1.js代码

onmessage = function(event){ var data = event.data; var dataArr = new Array(100); for(var i=0; i<100; i++){ dataArr[i] = parseInt(Math.random()*100); } //创建新的子进程 var worker2 = new Worker("worker3.js"); //worker.postMessage传递JSON对象 worker2.postMessage(JSON.stringify(dataArr)); worker2.onmessage = function(event){ //postMessage将数据返回给主页面 postMessage(event.data); } }

worker3.js代码

onmessage = function(event){ var numArr = JSON.parse(event.data); var returnNum = ""; for(var i =0; i<numArr.length; i++){ if (numArr[i]%3 ==0) { returnNum += numArr[i] + ";"; } } postMessage(returnNum); }

SharedWorker同享线程

同享线程
同享线程可以由两种方式来定义:1是通过指向 JavaScript 脚本资源的 URL 来创建,而是通过显式的名称。当由显式的名称来定义的时候,由创建这个同享线程的第1个页面中使用 URL 会被用来作为这个同享线程的 JavaScript 脚本资源 URL。通过这样1种方式,它允许同域中的多个利用程序使用同1个提供公共服务的同享线程,从而不需要所有的利用程序都去与这个提供公共服务的 URL 保持联系。

不管在甚么情况下,同享线程的作用域或是生效范围都是由创建它的域来定义的。因此,两个不同的站点(即域)使用相同的同享线程名称也不会冲突。

同享线程的创建
创建同享线程可以通过使用 SharedWorker() 构造函数来实现,这个构造函数使用 URL 作为第1个参数,即是指向 JavaScript 资源文件的 URL,同时,如果开发人员提供了第2个构造参数,那末这个参数将被用于作为这个同享线程的名称。创建同享线程的代码示例以下:

var worker = new SharedWorker('sharedworker.js', ’ mysharedworker ’ );

与同享线程通讯
同享线程的通讯也是跟专用线程1样,是通过使用隐式的 MessagePort 对象实例来完成的。当使用 SharedWorker() 构造函数的时候,这个对象将通过1种援用的方式被返回回来。我们可以通过这个援用的 port 端口属性来与它进行通讯。发送消息与接收消息的代码示例以下:

// 从端口接收数据 , 包括文本数据和结构化数据 worker.port.onmessage = function (event) { define your logic here... }; // 向端口发送普通文本数据 worker.port.postMessage('put your message here … '); // 向端口发送结构化数据 worker.port.postMessage( { username: 'usertext'; live_city: ['data-one', 'data-two', 'data-three','data- four']});

上面示例代码中,第1个我们使用 onmessage 事件处理器来接收消息,第2个使用 postMessage 来发送普通文本数据,第3个使用 postMessage 来发送结构化的数据,这里我们使用了 JSON 数据格式。

实例1:在单个页面中使用sharedWorker

<!DOCTYPE html> <html> <head> <title>单个页面的SharedWorker</title> </head> <body> <h2>单个页面的SharedWorker</h2> <div id="show"></div> <script type="text/javascript"> var worker = new SharedWorker('test.js'); var div = document.querySelector('#show'); worker.port.onmessage = function(e){ div.innerHTML = e.data; } </script> </body> </html>
onconnect = function(e){ var port = e.ports[0]; port.postMessage('你好!'); }

实例2:在多个页面中使用sharedWorker

<!DOCTYPE html> <html> <head> <meta charset="UTF⑻"> <title>在两个页面中同享后台线程</title> <script type="text/javascript"> var worker; function window_onload(){ worker = new SharedWorker('test.js'); var div = document.getElementById('div1'); worker.port.addEventListener('message', function(e) { div.innerHTML=e.data; }, false); worker.port.start(); worker.port.postMessage(1); } </script> </head> <body onload="window_onload()"> <h1>在两个页面中同享后台线程</h1> <div id="div1"></div> </body> </html>
onconnect = function(e) { var port = e.ports[0]; port.onmessage = function(e) { port.postMessage(e.data*e.data); } }

只要发送不同的数据就能够worker.port.postMessage(1);返回不同的结果。

实例3:在多个页面中,通过同享后台线程来同享数据

<!DOCTYPE html> <html> <head> <meta charset="UTF⑻"> <title>在多个页面中通过同享后台线程来同享数据</title> <script type="text/javascript"> var worker; function window_onload(){ worker = new SharedWorker('test2.js'); var div = document.getElementById('div1'); worker.port.addEventListener('message', function(e) { document.getElementById("text").value=e.data; }, false); worker.port.start(); } function SendData(){ worker.port.postMessage(document.getElementById("text").value); } function getData(){ worker.port.postMessage('get'); } </script> </head> <body onload="window_onload()"> <h1>在多个页面中通过同享后台线程来同享数据</h1> <input type="text" id="text"></input> <button onclick="SendData()">提交数据</button> <button onclick="getData()">获得数据</button> </body> </html>
onconnect = function(e) { var port = e.ports[0]; port.onmessage = function(e) { port.postMessage(e.data*e.data); } }

在1个页面中点击发送数据,然后在另外1个页面点击接受数据,可以得到发送的数据。

这里写图片描述

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐