js javascript 實(shi)現多線程(cheng)
在講之前,大家都知道js是基于單線程的,而這個線程就是瀏覽器的js引擎。
首先來看一下大家用的瀏覽器都具有那些線程吧。

假如(ru)我們要(yao)(yao)執行(xing)(xing)一(yi)些(xie)耗(hao)時(shi)的(de)(de)(de)操作,比如(ru)加載一(yi)張很大(da)的(de)(de)(de)圖片,我們可(ke)(ke)能需(xu)要(yao)(yao)一(yi)個進度條來讓用(yong)(yong)戶進行(xing)(xing)等待,在(zai)等待的(de)(de)(de)過(guo)程(cheng)(cheng)中,整個js線程(cheng)(cheng)會被阻塞,后面(mian)的(de)(de)(de)代(dai)碼(ma)不(bu)能正(zheng)常(chang)運行(xing)(xing),這可(ke)(ke)能大(da)大(da)的(de)(de)(de)降低用(yong)(yong)戶體驗,這時(shi)候(hou)我們就(jiu)期望擁有一(yi)個工作線程(cheng)(cheng)來處理這些(xie)耗(hao)時(shi)的(de)(de)(de)操作。在(zai)傳統(tong)的(de)(de)(de)html時(shi)代(dai)是(shi)基本(ben)不(bu)可(ke)(ke)能實現的(de)(de)(de),而(er)現在(zai),我們擁有一(yi)種叫做worker的(de)(de)(de)東西。它(ta)是(shi)js里(li)的(de)(de)(de)一(yi)個類,而(er)我們只需(xu)要(yao)(yao)創建它(ta)的(de)(de)(de)實例就(jiu)可(ke)(ke)以使(shi)用(yong)(yong)它(ta)。
var worker = new Worker(js file path);
構造函數的參數填上你的js文件的路徑,這個js文件將會在瀏覽器新開的線程里運行,而與原先的js引擎的線程并不影響。
下面看個例子。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<input type="text" name="ipt" id="ipt" value="" />
<button id="start">start</button>
<button id="stop">stop</button>
<button id="ale">alert</button>
<script type="text/javascript">
var ipt = document.getElementById("ipt");
var stop = document.getElementById("stop");
var start = document.getElementById("start");
var ale = document.getElementById("ale");
var worker = new Worker("js/test22.js");
worker.onmessage = function(){
ipt.value = event.data;
};
stop.addEventListener("click",function(){
//用于關閉worker線程
worker.terminate();
});
start.addEventListener("click",function(){
//開起worker線程
worker = new Worker("js/test22.js");
});
ale.addEventListener("click",function(){
alert("i'm a dialog");
});
</script>
</body>
</html>
下(xia)面是(shi)test22.js里(li)的代碼(ma),也(ye)就(jiu)是(shi)存(cun)在于worker線程(cheng)里(li)的代碼(ma)
var i = 0;
function mainFunc(){
i++;
//把i發送到瀏覽器的js引擎線程里
postMessage(i);
}
var id = setInterval(mainFunc,1000);
運行起來我們會發現

點擊確定后,它的數值并非2,而是一個比2更大的數

雖然(ran)dialog的(de)(de)彈(dan)出(chu)會阻塞js引(yin)擎線(xian)程(cheng)(cheng)(cheng),但(dan)是(shi)并不(bu)影響worker線(xian)程(cheng)(cheng)(cheng)的(de)(de)運行,所(suo)以(yi),在我(wo)們點擊(ji)確(que)定后,只(zhi)是(shi)在js引(yin)擎線(xian)程(cheng)(cheng)(cheng)上更新(xin)了(le)新(xin)的(de)(de)內容,而數值(zhi)是(shi)一直在跑動的(de)(de),這(zhe)就說明worker線(xian)程(cheng)(cheng)(cheng)和(he)原本(ben)的(de)(de)js線(xian)程(cheng)(cheng)(cheng)互(hu)不(bu)影響.
那么既然互不影響,兩(liang)個線程(cheng)之間要怎(zen)么來(lai)聯(lian)系(xi)呢,答(da)案其(qi)實(shi)已經(jing)在(zai)代碼里(li)了,那就是onPostMessage 和 onmessage這兩(liang)個函(han)數,其(qi)中onPostMessage(data)的(de)(de)參數是你要傳遞的(de)(de)數據(ju)(ju),而onmessage是一個回調(diao)函(han)數,只有(you)在(zai)接受(shou)到數據(ju)(ju)時,onmessage會被回調(diao),onmessage有(you)一個隱藏(zang)的(de)(de)參數,那就是event,我們可(ke)以用event.data獲取到傳遞過來(lai)的(de)(de)數據(ju)(ju)來(lai)更新(xin)主線程(cheng)。
使用worker線程應注意的是,所有js里集成的對象都在js線程里,而并非worker線程。
例如我(wo)們在worker線程里寫(xie)上:
var a = document.getElementById("a");
結(jie)果你(ni)會得到(dao)一條Error,告訴你(ni)找(zhao)不(bu)到(dao)document,或者document is undefined。所以我(wo)們盡(jin)量(liang)把需要的(de)東西都寫到(dao)主線程(cheng)里,而只把耗時的(de)操作寫到(dao)worker線程(cheng)里。
