web worker其實是開啓js異步執行的一種方式。在html5以前有事件、定時器、http請求三種異步機制,js自己並不能主動將一塊代碼使用異步的方式執行,worker的出現填補了js在非事件、定時器、http請求的狀況下能夠主動開啓js代碼的異步執行。worker有本身獨立的線程,並不是像前面三個異步機制那樣的回調函數。因此,worker線程一旦創建成功,就會始終運行,並不會像前面三個異步機制那樣被主線程打斷,主線程與輔助線程(worker)之間經過消息事件通信。html
web worker相關手冊與博客:html5
阮一峯網絡日誌:http://www.ruanyifeng.com/blog/2018/07/web-worker.htmlweb
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多線程
1.同源限制:分配worker線程運行腳本文件,必須與主線程的腳本文件同源。異步
2.DOM限制:worker線程所在的全局對象,與主線程不同,不能讀取所在網頁的DOM對象,也沒法使用document 、 window 、parent這些對象。可是worker線程可使用navigator對象和location對象。ide
3.通訊聯繫:worker線程和主線程不在同一個上下文環境,它們不能直接通訊,必須經過消息完成。函數
4.腳本限制:worker線程不能執行alert()方法和cnfirm()方法,但可使用XMLHttpRequest對象發送AJAX請求。post
5.文件限制:worker線程沒法讀取本地文件,即不能打開本機的文件系統(file://),它所加載的腳本必須來自網絡。
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 }
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>
otherWindow.postMessage(message, targetOrigin, [transfer]);
otherWindow:窗口引用,好比window.parent、window.iframes[n];
message:須要傳遞的數據,不能使用function;
targetOrigin:可使用URL(如示例中,窗口協議、主機地址、端口必須一致),也能夠直接使用窗口對象模型的引用,好比示例中參數也可使用window.parent。
[transfer]:(暫時還不瞭解其如何使用)
window.addEventListener("message", receiveMessage, false);
message除了示例中的data接收postMessage傳遞的數,還有origin攜帶了傳遞數據的窗口的URL,以及source攜帶的傳遞數據的窗口對象模型。