js多線程解決方案Web?Worker簡單說明與實例演示
一、什么是Web Worker ?
JavaScript 語言是采用單線程模型,也就是任務只能在一個線程上完成,一次只能做一件事,前面任務沒執(zhí)行完,后面的任務只能排隊等待,由于多核 CPU 的出現(xiàn),單線程帶來很大不便,無法充分發(fā)揮計算機的能力。
Web Worker 就是為了 javascript 創(chuàng)造多線程而生的,主線程創(chuàng)建 worker 子線程,將一些任務分配給后臺運行,等到子線程完成計算任務,再把結果返回給主線程,好處是計算密集型或高延遲的任務被 worker 負擔了,主線程就會很流暢。網(wǎng)頁加載展示可分為兩部分:主進程也叫 UI 進程,子進程也叫工作進程,子進程不能控制 UI 進程,只能進行數(shù)據(jù)交互。
Web Worker 子線程一旦創(chuàng)建成功,就會獨立于其他腳本始終運行,不會被主線程上活動打斷。這樣有利于隨時響應主線程的通信。但是這也造成 Worker 比較耗費資源,不應該過度使用,使用完畢之后應該關閉。
使用 Web Worker 注意點:
- 同源限制:分配給 Worker 線程運行的腳本,必須與主線程的腳本文件同源,否則存在跨域問題。
- DOM限制:Worker 線程所在的全局對象,與主線程不同,無法讀取主線程的DOM對象,也無法使用 window、document、parent 這些對象。但是Worker線程可以使用navigation和location對象。
- 數(shù)據(jù)通信:Worker 線程與主線程不在一個環(huán)境,不能直接通信,必須通過消息來完成數(shù)據(jù)通信。
- 腳本限制:Worker 線程不能執(zhí)行 window 的 alert、confirm 方法。但是可以通過ajax發(fā)送請求。
- 文件限制:Worker線程無法讀取本地文件,子線程加載的腳本必須來自網(wǎng)絡。
相關API
1.Worker:構造函數(shù),加載分線程執(zhí)行的js文件
2.Worker.prototype.onmessage:用于接受另一個線程的回調函數(shù)
3.WorKer.prototype.postMessage:向另一個線程發(fā)送消息
**不足**
worker內代碼不能操作DOM
不能跨域加載JS
不是每個瀏覽器都支持這個新特性
var input = document.getElementById('number')
function computed(n){
return n<=2 ? 1:computed(n-1) + computed(n-2) //遞歸調用
}
document.getElementById('btn').onclick = function(){
var number = input.value
var result = computed(number)
alert(result)
}
上面代碼當按鈕被點擊時根據(jù)用戶輸入的值進行斐波拉契數(shù)列的計算
當這個值較大時,由于遞歸導致頁面要很長時間才能響應,在等待響應的過程中由于js的單線程機制導致我們不能進行任何操作,頁面就像被卡死了一樣,如果要解決這個問題,可以用 web Wokers實現(xiàn)
將計算的邏輯交給分線程執(zhí)行,這樣在計算的過程中我們可以正常操作頁面
//index.html
var input = document.getElementById('number')
document.getElementById('btn').onclick = function(){
var number = input.value
//創(chuàng)建一個worker對象
var worker = new Worker('./js/worker.js')
console.log(worker)
//向分線程發(fā)送消息
worker.postMessage(number)
console.log('主線程向分線程發(fā)送數(shù)據(jù):'+number)
//綁定接受消息的監(jiān)聽
worker.onmessage = function(event){
console.log('主線程接受分線程返回的數(shù)據(jù):'+event.data)
}
}
//worker.js
function computed(n){
return n<=2 ? 1:computed(n-1) + computed(n-2) //遞歸調用
}
var onmessage = function(event){
var number = event.data
console.log('分線程接受主線程發(fā)送的數(shù)據(jù):'+number)
//計算
var result = computed(number)
postMessage(result)
console.log('分線程向主線程返回數(shù)據(jù):'+number)
}
二、使用語法
2.1 創(chuàng)建Worker線程:
創(chuàng)建worker之前,先檢查瀏覽器是否支持它。使用 typeof 檢查,代碼如下:
if( typeof Worker !== undefined ){
console.log("支持Worker線程")
}else{
console.log("不支持Worker")
}檢查瀏覽器支持 worker 之后,主線程使用 new 命令,調用 worker() 構造函數(shù),新建 Worker 線程。
var myWorker = new Worker('worker.js')構造函數(shù)的參數(shù)是一個腳本文件,該文件不能是本地文件,必須來自網(wǎng)絡腳本,該文件就是Worker 線程要執(zhí)行的任務。如果該文件加載失敗,Worker 就會失敗。
2.2 主線程與子線程數(shù)據(jù)通信:
主線程調用 postMessage() 方法,向 Worker 發(fā)消息。postMessage(參數(shù)) 方法中參數(shù)就是傳給 Worker 的數(shù)據(jù),這個數(shù)據(jù)可以是任意格式。
myWorker.postMessage("你好")緊接著 Worker 線程,通過 onmessage 指定監(jiān)聽函數(shù),接收消息。worker.js 代碼如下:
this.onmessage = function(res){
console.log("接收到消息",res.data)
this.postMessage("我收到消息了")
}worker子進程收到消息之后,可以繼續(xù)向主進程發(fā)送消息,使用 postMessage()。代碼如上。
主進程也通過onmessage監(jiān)聽函數(shù)接收消息。
myWorker.onmessage = function(res){
console.log("主線程收到消息:",res.data)
}2.3 Worker線程
Worker線程內部,添加 this.onmessage 監(jiān)聽函數(shù),其中 this 是子線程的全局對象,也可以替換成 self,self 代表子線程本身。等同于:
self.onmessage 《=》 this.onmessage
除了使用 self.onmessage 指定監(jiān)聽函數(shù),也可以使用 this.addEventListener() 監(jiān)聽事件對象。上述 worker.js 代碼可改為:
//寫法一
this.addEventListener("message",function(res){
console.log("res",res.data)
})
//寫法二
addEventListener("message",function(res){
this.console.log("1",res.data)
})2.4 錯誤處理
主線程可以監(jiān)聽Worker是否發(fā)生錯誤,如果發(fā)生錯誤,Worker 會觸發(fā)主線程的 error 事件。
// 寫法一
myWorker.onerror = function(e){
console.log('e',e)
}
//寫法二
myWorker.addEventListener("error",function(e){
console.log("e",e)
})worker 子線程也可以監(jiān)聽 error 事件。
2.5 關閉 Worker
Worker 比較耗費資源,不應該過度使用,使用完畢之后應該關閉。主線程和子線程都可以關閉。
//主線程關閉 myWorker.terminate() //子線程關閉 self.close() //方法一 this.close() //方法二
三、同一個網(wǎng)頁的Web Worker
通常情況下,Worker 載入的是一個單獨的 javascript 文件,但是也可以載入與主線程在同一個網(wǎng)頁的代碼。網(wǎng)頁中添加 Worker 腳本,必須注意指定script標簽的type屬性是一個瀏覽器不認識的值,否則就會失去意義。如:
<script type="app/worker" id="wrs">
this.onmessage = function(res){
console.log("接收參數(shù)",res.data)
}
</script>然后,需要讀取這段代碼,先將嵌入網(wǎng)頁的腳本代碼轉成二進制對象,然后為這個二進制對象生成url,再讓worker加載url,這樣就實現(xiàn)了主進程和worker在同一個網(wǎng)頁內。代碼如下:
<script>
var blob = new Blob([document.querySelector("#wrs").textContent]);
var url = window.URL.createObjectURL(blob);
var worker = new Worker(url)
worker.postMessage("發(fā)送數(shù)據(jù)")
</script>四、Worker 屬性和方法總結
Worker構造函數(shù)方法:
- Worker.postMessage() - 發(fā)送消息。
- Worker.onmessage() - 監(jiān)聽子線程發(fā)送過來的數(shù)據(jù)。
- Worker.onmessageerror() - 發(fā)送數(shù)據(jù)無法序列化時觸發(fā)事件。
- Worker.onerror() - 錯誤處理。
- Worker.terminate() - 結束Worker。
子進程屬性方法:
Worker() 構造函數(shù),可以接受兩個參數(shù),第一個是腳本的地址,第二個是參數(shù)是配置對象,該對象指定Worker的名稱。如:
var myWorker = new Worker('worker.js', { name : 'myWorker' });- self.name - Worker 的名字
- self.onmessage - 接收消息
- self.postmessage - 發(fā)送數(shù)據(jù)
- self.onerror - 錯誤處理
- self.onmessageerror - 發(fā)送的數(shù)據(jù)無法序列化成字符串時觸發(fā)事件
- self.close - 關閉Worker線程
- self.importScript() - 加載js腳本
以上就是js多線程解決方案Web Workers簡單說明與實例演示的詳細內容,更多關于js多線程解決方案Web Workers說明的資料請關注腳本之家其它相關文章!
相關文章
JavaScript與DOM組合動態(tài)創(chuàng)建表格實例
這篇文章簡單介紹了DOM 1.0一些基本而強大的方法以及如何在JavaScript中使用它們;你可以學到如何動態(tài)地創(chuàng)建、獲取、控制和刪除HTML元素2012-12-12
網(wǎng)絡傳輸協(xié)議(http協(xié)議)
網(wǎng)絡傳輸協(xié)議(http協(xié)議)指服務器和客戶端間進行通信時的約束和規(guī)范,客戶端與服務端的數(shù)據(jù)交互并不是雜亂無章的,需要遵照(基于)一定的規(guī)范進行,本文主要介紹http超文本傳輸協(xié)議。希望對大家有所幫助2016-11-11
JS失效 提示HTML1114: (UNICODE 字節(jié)順序標記)的代碼頁 utf-8 覆蓋(META 標記)的沖突的代
今天使用F12調試的時候提示HTML1114: (UNICODE 字節(jié)順序標記)的代碼頁 utf-8 覆蓋(META 標記)的沖突的代碼頁 utf-8,需要的朋友可以參考下2017-06-06

