**轉自博客原文連接:https://tong-h.github.io/2019/04/21/webworker/
**
最近使用 iframe 的時候想要獲取 iframe 文檔信息的時候遇到了跨域問題呻疹,最后使用 postmessage 做父子頁面通信解決需求也順便學習了下 webworker 的使用
webWoker 使用依賴 postMessage() 和 onMessage(), 所以先說這兩個吧
postMessage && onMessage
- 提供網頁文檔之間互相發(fā)送和接收信息的功能筹陵,可用于解決跨域訪問的問題
- 會在所有頁面腳本執(zhí)行完畢之后(包括方法之后或者之前設置的timeout 事件)再執(zhí)行
- 掛載于window對象上
postMessage 語法: otherWindow.postMessage(message, targetOrigin, [transfer]);
??message: 發(fā)送的數據,不限類型朦佩,因為他自己會序列化
??targetOrigin:通過窗口的origin屬性指定哪些窗口能接收到消息事件,其值可以是字符串"*"(表示無限制)或者一個URI
??transfer:可選參數宋彼;一個 Transferable 對象([什么是Transferable[(https://developer.mozilla.org/zh-CN/docs/Web/API/Transferable))仙畦,和message 同時傳遞的,對象的所有權將被轉移給消息的接收方,而發(fā)送一方將不再保有所有權
onMessage 語法:
window.addEventListener('message', function(event) { ... })
window.onmessage = function(event) { ... }
獲取到的 event 對象包含
??data:接收的數據對象慨畸,對應 postMessage 的 message 參數
??origin:消息發(fā)送方窗口的 origin,字符串由 協(xié)議檐什、“://“弱卡、域名乃正、“ : 端口號”拼接而成
??source:對發(fā)送消息的窗口對象的引用
舉個小栗子
- 父頁面向子頁面?zhèn)髦?/li>
// 在 iframe 加載完畢后婶博,獲取 iframe 的 window 對象,調用 postMessage 方法
<body>
<div>a page</div>
<iframe src="b.html" id="frame"></iframe>
<script>
var frame = document.getElementById('frame')
frame.onload = function(){
frame.contentWindow.postMessage({ name: 'a page' },'*');
}
</script>
</body>
// 子頁面監(jiān)聽 message 事件設置回調打印 event
<body>
<div>b page</div>
<script>
window.addEventListener("message", (event) => console.log('this b page', event), false);
</script>
</body>
- 子頁面向父頁面?zhèn)髦?/li>
// 父頁面監(jiān)聽 message 事件設置回調打印 event
<body>
<div>a page</div>
<iframe src="b.html" id="frame"></iframe>
<script>
window.addEventListener("message", (event) => console.log('this a page', event), false);
</script>
</body>
// 使用 parent 獲取 window 對象名党,調用 postMessage 方法
<body>
<div>b page</div>
<script>
console.log(parent)
parent.postMessage( {name: 'b page'}, '*');
</script>
</body>
Workers
- 我自己感覺很多比較麻煩耗內存的js邏輯操作都可以放在worker里,比如輪詢服務器狀態(tài)或者一些很耗時量很大的數據操作用
- 讓腳本在瀏覽器后臺線程中運行
- 在worker內条获,不能直接操作DOM節(jié)點蒋歌,也不能使用window對象的默認方法和屬性帅掘,window對象下可用的方法
- worker 中也能再創(chuàng)建 worker
- 由于安全限制 Worker 不能讀取本地文件,所以腳本必須來自網絡堂油,讀取本地文件會報錯 "Uncaught SecurityError: Failed to create a worker: script at '(path)/worker.js' cannot be accessed from origin 'null'."
- 關于兼容性
用法
在使用 worker 的 js文件里
// 使用 Worker() 指定腳本 url 創(chuàng)建一個新的 worker
// 參數就是 Worker 線程所要執(zhí)行的任務
// Worker 使用 postMessage 和 onMessage 進行通信
var myWorker = new Worker("worker.js");
// 使用 postMessage() 和 onMessage() 發(fā)送和接收數據
myWorker.postMessage("request");
在 worker.js文件
// 消息響應
onmessage = function(e) {
console.log(e.data);
console.log(self)
// 消息回傳
postMessage(workerResult);
}
關閉/錯誤/加載腳本
// 在 main.js 文件中,強制終止
worker.terminate();
// 在 worker 線程中吱窝,自己關閉
self.close();
// error 錯誤代理
worker.onerror(function (event) {});
// 發(fā)送的數據無法序列化成字符串時迫靖,會觸發(fā)這個事件
Worker.onmessageerror(function (event) {});
// worker 使用 importScripts() 加載腳本,可以加載多個
importScripts('script1.js', 'script2.js');
小栗子
如果你現在沒有條件加載網絡上的文件系宜,可以使用 URL.createObjectURL 方法建立緩存 URL
可以試著運行一下面兩個頁面感受一下
可以運行一下這個頁面,一個普通的 for 循環(huán)俩垃,因為數字太大運行時會有明顯的卡頓
<html>
<head>
<title>Test Web worker</title>
<script type="text/JavaScript">
window.onload = function(){
for(var num=99;num<1000000000;num++){
document.getElementById("numshow").innerHTML += event.data+"<br/>";
}
}
</script>
</head>
<body id="numshow">
</body>
</html>
這個可以使用 URL.createObjectURL 方法建立緩存 URL
<html>
<head>
<title>Test Web worker</title>
<script type="text/JavaScript">
window.onload = function() {
console.log(5);
var worker = new Worker(URL.createObjectURL(new Blob(["(" + webWorker.toString() + ")()"], {type: 'text/javascript'})));
worker.onmessage= (event) => {
// 數據打印
console.log(event.data);
document.getElementById("numshow").innerHTML += event.data+"<br/>";
// 向 worker 線程發(fā)送數據
event.data === 1 ? worker.postMessage('num'):''
};
}
function webWorker() {
// worker 對象 self
console.log(self)
// 接收來自主線程的數據
self.onmessage = function (event) {
console.log(event.data);
}
for (var num = 1; num < 1000000000; num++) {
// 當 num === 200的時候關閉 worker 線程
num === 200 ? (postMessage("worker關閉"), close()) : postMessage(num**2)
}
}
</script>
</head>
<body id="numshow">
</body>
</html>
參考文章
postMessage:MDN https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage
webworker:MDN https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API/Using_web_workers
阮一峰:http://www.ruanyifeng.com/blog/2018/07/web-worker.html