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

