Home > Article > Web Front-end > html5 multi-threading webWorker
Web Worker provides a simple way to enable web content to run scripts in the background. Once a worker is created, it can pass messages to the event listener function specified by its creator, so that all tasks generated by the worker will receive these messages
The worker thread can pass messages without interfering with the UI Perform tasks. In addition, it can also use XMLHttpRequest (although the responseXML and channel attribute values are always null) to perform I/O operations.
Creating a new worker is very simple. All you have to do is call the Worker() constructor, specifying the URI of a script to run within the worker thread. If you want to be notified by the worker, you can set the worker's onmessage attribute to a specific event handler.
var myWorker = new Worker("my_task.js"); myWorker.onmessage = function (oEvent) { console.log("Called back by the worker!\n"); };
Alternatively, you can use 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.
The first line in the example creates a new worker thread. The third line sets the listener function for the message event on the worker. This event handler is called when the worker calls its own postMessage() function. Finally, line 7 starts the worker thread.
The data transferred between the main page and the worker is through copying instead of sharing Completed. The object passed to the worker needs to be serialized, and then deserialized at the other end. The page and worker do not share the same instance, and the end result is that a copy of the data is generated at the end of each communication. Most browsers use structured copy to implement this feature.
Example: Create a sub-thread to calculate the sum
<!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); }
You can hand over the time-consuming processing to a background thread for processing, and then send the result after processing Return to the main page.
Data interaction between threads transfers information to each other by sending and receiving messages. The main thread first Create a Worker and pass the data to the background thread through the postMessage method of the Worker object. The main program listens to the background and returns the results of the background thread processing through the onmessage event or the custom addEventListener
event. Similarly, the background thread receives the data passed by the main page through the onmessage event, and returns the processing results to the main page through postMessage.
Example: The page sequence randomly generates 100 data, and passes the data to the background thread for filtering. The data that can be evenly divided by 3 is returned to the main page and displayed in the form of a dynamic table.
<!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); }
Sub-threads can be nested in threads, so that a larger background thread can be divided into several sub-threads. Each sub-thread grid completes relatively independent work.
Still using the above example, construct an example of single-layer sub-thread nesting. Put the previous work of generating random numbers on the main page into a background thread, and then construct a sub-thread in the background thread to select data that can be divided by 3. The data passed is in JSON data format.
<!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 sub-thread code
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 code
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(); }
When delivering messages to sub-threads, use worker.postMessage. When submitting data to the main page, use postMessage directly.
<!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 code
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 code
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); }
shared thread
Shared threads can be defined in two ways: first, by creating a URL pointing to a JavaScript script resource, but by explicitly naming it. When defined by an explicit name, the URL used in the first page that created the shared thread will be used as the JavaScript script resource URL for the shared thread. In this way, it allows multiple applications in the same domain to use the same shared thread that provides a common service, thereby eliminating the need for all applications to maintain contact with the URL that provides a common service.
No matter what the circumstances, the scope or effective scope of a shared thread is defined by the domain in which it is created. Therefore, two different sites (i.e. domains) using the same shared thread name will not conflict.
共享线程的创建
创建共享线程可以通过使用 SharedWorker() 构造函数来实现,这个构造函数使用 URL 作为第一个参数,即是指向 JavaScript 资源文件的 URL,同时,如果开发人员提供了第二个构造参数,那么这个参数将被用于作为这个共享线程的名称。创建共享线程的代码示例如下:
var worker = new SharedWorker('sharedworker.js', ’ mysharedworker ’ );
与共享线程通信
共享线程的通信也是跟专用线程一样,是通过使用隐式的 MessagePort 对象实例来完成的。当使用 SharedWorker() 构造函数的时候,这个对象将通过一种引用的方式被返回回来。我们可以通过这个引用的 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']});
上面示例代码中,第一个我们使用 onmessage 事件处理器来接收消息,第二个使用 postMessage 来发送普通文本数据,第三个使用 postMessage 来发送结构化的数据,这里我们使用了 JSON 数据格式。
实例1:在单个页面中使用sharedWorker
<!DOCTYPE html><html><head> <title>单个页面的SharedWorker</title></head><body> <h2>单个页面的SharedWorker</h2> <p id="show"></p> <script type="text/javascript"> var worker = new SharedWorker('test.js'); var p = document.querySelector('#show'); worker.port.onmessage = function(e){ p.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-8"><title>在两个页面中共享后台线程</title><script type="text/javascript">var worker;function window_onload(){ worker = new SharedWorker('test.js'); var p = document.getElementById('p1'); worker.port.addEventListener('message', function(e) { p.innerHTML=e.data; }, false); worker.port.start(); worker.port.postMessage(1); }</script></head><body onload="window_onload()"><h1>在两个页面中共享后台线程</h1><p id="p1"></p></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-8"><title>在多个页面中通过共享后台线程来共享数据</title><script type="text/javascript">var worker;function window_onload(){ worker = new SharedWorker('test2.js'); var p = document.getElementById('p1'); 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); } }
在一个页面中点击发送数据,然后在另外一个页面点击接受数据,可以得到发送的数据。
Web Worker提供了一个简单的方法使得 web 内容能够在后台运行脚本。一旦 worker 创建后,它可以向由它的创建者指定的事件监听函数传递消息,这样该 worker 生成的所有任务就都会接收到这些消息
worker 线程能够在不干扰 UI 的情况下执行任务。另外,它还能够使用 XMLHttpRequest (虽然 responseXML 与 channel 两个属性值始终是 null)来执行 I/O 操作。
创建一个新的 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"); //把随机数组提交给子线程进行挑选工作 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); }
共享线程
共享线程可以由两种方式来定义:一是通过指向 JavaScript 脚本资源的 URL 来创建,而是通过显式的名称。当由显式的名称来定义的时候,由创建这个共享线程的第一个页面中使用 URL 会被用来作为这个共享线程的 JavaScript 脚本资源 URL。通过这样一种方式,它允许同域中的多个应用程序使用同一个提供公共服务的共享线程,从而不需要所有的应用程序都去与这个提供公共服务的 URL 保持联系。
无论在什么情况下,共享线程的作用域或者是生效范围都是由创建它的域来定义的。因此,两个不同的站点(即域)使用相同的共享线程名称也不会冲突。
共享线程的创建
创建共享线程可以通过使用 SharedWorker() 构造函数来实现,这个构造函数使用 URL 作为第一个参数,即是指向 JavaScript 资源文件的 URL,同时,如果开发人员提供了第二个构造参数,那么这个参数将被用于作为这个共享线程的名称。创建共享线程的代码示例如下:
var worker = new SharedWorker('sharedworker.js', ’ mysharedworker ’ );
与共享线程通信
共享线程的通信也是跟专用线程一样,是通过使用隐式的 MessagePort 对象实例来完成的。当使用 SharedWorker() 构造函数的时候,这个对象将通过一种引用的方式被返回回来。我们可以通过这个引用的 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']});
上面示例代码中,第一个我们使用 onmessage 事件处理器来接收消息,第二个使用 postMessage 来发送普通文本数据,第三个使用 postMessage 来发送结构化的数据,这里我们使用了 JSON 数据格式。
实例1:在单个页面中使用sharedWorker
<!DOCTYPE html><html><head> <title>单个页面的SharedWorker</title></head><body> <h2>单个页面的SharedWorker</h2> <p id="show"></p> <script type="text/javascript"> var worker = new SharedWorker('test.js'); var p = document.querySelector('#show'); worker.port.onmessage = function(e){ p.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-8"><title>在两个页面中共享后台线程</title><script type="text/javascript">var worker;function window_onload(){ worker = new SharedWorker('test.js'); var p = document.getElementById('p1'); worker.port.addEventListener('message', function(e) { p.innerHTML=e.data; }, false); worker.port.start(); worker.port.postMessage(1); }</script></head><body onload="window_onload()"><h1>在两个页面中共享后台线程</h1><p id="p1"></p></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-8"><title>在多个页面中通过共享后台线程来共享数据</title><script type="text/javascript">var worker;function window_onload(){ worker = new SharedWorker('test2.js'); var p = document.getElementById('p1'); 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); } }
在一个页面中点击发送数据,然后在另外一个页面点击接受数据,可以得到发送的数据。
以上就是html5 多线程处理webWorker的内容,更多相关内容请关注PHP中文网(www.php.cn)!