HTML5之worker開啟JS多線程模式及window.postMessage跨域


  • worker概述
  • worker基本使用
  • window下的postMessage
  • worker多線程的應用

 一、worker概述

web worker實際上是開啟js異步執行的一種方式。在html5之前有事件、定時器、http請求三種異步機制,js本身並不能主動將一塊代碼使用異步的方式執行,worker的出現填補了js在非事件、定時器、http請求的情況下可以主動開啟js代碼的異步執行。worker有自己獨立的線程,並非像前面三個異步機制那樣的回調函數。所以,worker線程一旦建立成功,就會始終運行,並不會像前面三個異步機制那樣被主線程打斷,主線程與輔助線程(worker)之間通過消息事件通訊。

web worker相關手冊與博客:

阮一峰網絡日志:http://www.ruanyifeng.com/blog/2018/07/web-worker.html

MDN手冊:https://developer.mozilla.org/zh-CN/docs/Web/API/Worker

developer博客:https://www.developer.com/lang/jscript/7-things-you-need-to-know-about-web-workers.html

上一篇博客的翻譯版:https://blog.csdn.net/shenlei19911210/article/details/49779613

web worker使用注意事項:

1.同源限制:分配worker線程運行腳本文件,必須與主線程的腳本文件同源。

2.DOM限制:worker線程所在的全局對象,與主線程不一樣,不能讀取所在網頁的DOM對象,也無法使用document 、 window 、parent這些對象。但是worker線程可以使用navigator對象和location對象。

3.通信聯系:worker線程和主線程不在同一個上下文環境,它們不能直接通信,必須通過消息完成。

4.腳本限制:worker線程不能執行alert()方法和cnfirm()方法,但可以使用XMLHttpRequest對象發送AJAX請求。

5.文件限制:worker線程無法讀取本地文件,即不能打開本機的文件系統(file://),它所加載的腳本必須來自網絡。

 二、worker的基本使用

2.1在主線程中開啟一個輔助線程:

var worker = new Worker('./worker.js'); //在主線程的中開啟輔助線程(傳入輔助線程的文件路徑)

2.2主線程向輔助線程發送消息:

1 var data = {type:'sum',num:1000}//測試Function類型的值不能傳遞
2 worker.postMessage(data);//通過postMessage方法傳遞給輔助線程

2.3輔助線程接收主線程的消息:

1 this.onmessage = function(e){//在輔助線程中通過onmessage事件監聽主線程postMessage發送過來的消息
2     console.log(e);//通過事件元對象中的data接收主線程發送過來的數據
3     console.log(e.data.num)
4 }

2.4.輔助線程向主線程提交工作(第5行代碼):

 1 this.onmessage = function(e){//在輔助線程中通過onmessage事件監聽主線程postMessage發送過來的消息
 2     var submitWorker = null;
 3     if(e.data.type == 'sum'){
 4         submitWorker = sum(e.data.num); //輔助線程處理業務
 5         this.postMessage(submitWorker); //輔助線程通過postMessage方法向主線程提交工作
 6     }
 7 }
 8 function sum(num){
 9     var sumVal = 0;
10     for(var i = 0; i < num; i++){
11         sumVal +=i;
12     }
13     return sumVal;
14 }

2.5主線程接收輔助線程的工作:

1 worker.onmessage = function(e){//主線程通過onmessage監聽接收輔助線程的消息
2     console.log(e);// 同樣通過事件元對象的data獲取輔助線程傳遞過來的數據
3     console.log(e.data);//499500
4 }

2.6主線程辭退輔助線程與輔助線程主動關閉線程:

1 worker.terminate(); //主線程主動關閉輔助線程worker (辭退后不在接收輔助線程的消息)
2 this.close(); //輔助線程主動關閉線程(關閉后不再向主線程發送消息)

以上示例的全部代碼,請注意需要在網絡服務下測試,因為worker必須來自網絡。

 1 //indexWorker.html(主線程代碼)
 2 <!DOCTYPE html>
 3 <html>
 4 <head>
 5     <meta charset="utf-8">
 6     <meta http-equiv="X-UA-Compatible" content="IE=edge">
 7     <title>worker</title>
 8     <link rel="stylesheet" href="">
 9 </head>
10 <body>
11     <script>
12         var worker = new Worker('./worker.js');
13         var data = {
14             type:'sum',
15             num:1000
16         }
17         worker.postMessage(data);//主線程向輔助線程發送消息
18         worker.onmessage = function(e){//主線程接收輔助線程的消息
19             console.log(e);// 同樣通過事件元對象的data獲取輔助線程傳遞過來的數據
20             console.log(e.data);//499500
21             // worker.terminate(); //主線程主動關閉輔助線程worker
22         }
23 
24     </script>
25 </body>
26 </html>
27 
28 //worker.js(輔助線程腳本代碼)
29 this.onmessage = function(e){//在輔助線程中通過onmessage事件監聽主線程postMessage發送過來的消息
30     // console.log(e);//通過事件元對象中的data接收主線程發送過來的數據
31     var submitWorker = null;
32     if(e.data.type == 'sum'){
33         submitWorker = sum(e.data.num); //輔助線程處理業務
34         this.postMessage(submitWorker); //輔助線程通過postMessage方法向主線程提交工作
35     }
36     // this.close(); //輔助線程主動關閉線程(關閉后不再向主線程發送消息)
37 }
38 function sum(num){
39     var sumVal = 0;
40     for(var i = 0; i < num; i++){
41         sumVal +=i;
42     }
43     return sumVal;
44 }
示例代碼(兩個文件的代碼,注意自己拆分)

2.7worker中引入其他腳本:

1 importScripts('script1.js'); //可以在輔助線程腳本中通過importScripts引入其他腳本
2 importScripts('script1.js', 'script2.js');//並且可以同時加載多個腳本

比如可以通過腳本引入的方式來拆分上面的worker.js文件==》

 1 //worker.js文件
 2 importScripts('./workerMath.js'); //通過importScripts()方法引入其他腳本文件
 3 this.onmessage = function(e){//在輔助線程中通過onmessage事件監聽主線程postMessage發送過來的消息
 4     // console.log(e);//通過事件元對象中的data接收主線程發送過來的數據
 5     var submitWorker = null;
 6     if(e.data.type == 'sum'){
 7         submitWorker = sum(e.data.num); //輔助線程處理業務
 8         this.postMessage(submitWorker); //輔助線程通過postMessage方法向主線程提交工作
 9     }
10     // this.close(); //輔助線程主動關閉線程(關閉后不再向主線程發送消息)
11 }
12 
13 //workerMath.js文件
14 function sum(num){
15     var sumVal = 0;
16     for(var i = 0; i < num; i++){
17         sumVal +=i;
18     }
19     return sumVal;
20 }
View Code

 三、window下的postMessage

MDN手冊:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage

window下的postMessage與worker中的postMessage的功能基本一致,只不過一個是實現js腳本線程之間的通信,一個是實現兩個網頁之間的通信。window中的postMessage主要被應用與解決主窗口與iframe子窗口中的數據傳遞,並且可以實現跨域通信。

示例:

 1 //父窗口代碼
 2 <iframe src="./winPostMessage.html"></iframe>
 3 <script>
 4     window.onmessage = function(e){
 5         console.log(e);
 6         console.log(e.data.name);//他鄉踏雪
 7     }
 8 </script>
 9 
10 //子窗口代碼
11 <script>
12     window.parent.postMessage({name:"他鄉踏雪"},'http://localhost/')
13 </script>

postMessage語法:

otherWindow.postMessage(message, targetOrigin, [transfer]);

otherWindow:窗口引用,比如window.parent、window.iframes[n];

message:需要傳遞的數據,不能使用function;

targetOrigin:可以使用URL(如示例中,窗口協議、主機地址、端口必須一致),也可以直接使用窗口對象模型的引用,比如示例中參數也可以使用window.parent。

[transfer]:(暫時還不了解其如何使用)

onmessage事件

window.addEventListener("message", receiveMessage, false);

message除了示例中的data接收postMessage傳遞的數,還有origin攜帶了傳遞數據的窗口的URL,以及source攜帶的傳遞數據的窗口對象模型。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM