【worker】js中的多线程
? ? ? 因?yàn)橄聜€(gè)項(xiàng)目中要用到一些倒計(jì)時(shí)的功能,所以就提前準(zhǔn)備了一下,省的到時(shí)候出現(xiàn)一下界面不友好和一些其他的事情。正好趁著這個(gè)機(jī)會(huì)也加深一下html5中的多線程worker的用法和理解。
Worker簡(jiǎn)介
? ? JavaScript 語(yǔ)言采用的是單線程模型,也就是說(shuō),所有任務(wù)只能在一個(gè)線程上完成,一次只能做一件事。前面的任務(wù)沒做完,后面的任務(wù)只能等著。這些都是我們所公知的。但是隨著業(yè)務(wù)的不斷增加,只是單純的單線程模式已經(jīng)可能無(wú)法滿足我們的需求了。于是在html5中新增了后臺(tái)任務(wù)worker API。
w3c中的介紹:web worker 是運(yùn)行在后臺(tái)的 JavaScript,獨(dú)立于其他腳本,不會(huì)影響頁(yè)面的性能。您可以繼續(xù)做任何愿意做的事情:點(diǎn)擊、選取內(nèi)容等等,而此時(shí) web worker 在后臺(tái)運(yùn)行。
? ? ? ?worker就是為了JavaScript 創(chuàng)造多線程環(huán)境,允許主線程創(chuàng)建 Worker 線程,將一些任務(wù)分配給后者運(yùn)行。開啟后臺(tái)線程,在不影響前臺(tái)線程的前提下做一些耗時(shí)或者異步的操作。因?yàn)槭遣煌木€程,所以主線程與worker線程互不干擾。也不會(huì)相互打斷。所以在一些場(chǎng)景可以提高頁(yè)面的流程性。Worker 線程一旦新建成功,就會(huì)始終運(yùn)行,不會(huì)被主線程上的活動(dòng)(比如用戶點(diǎn)擊按鈕、提交表單)打斷。這樣有利于隨時(shí)響應(yīng)主線程的通信。但是,這也造成了 Worker 比較耗費(fèi)資源,不應(yīng)該過度使用,而且一旦使用完畢,就應(yīng)該關(guān)閉。
使用規(guī)則
worker文檔
Web Workers API的Worker界面代表了一個(gè)可以輕松創(chuàng)建的后臺(tái)任務(wù),可以將消息發(fā)送回其創(chuàng)建者。創(chuàng)建worker就像調(diào)用?構(gòu)造函數(shù)并指定要在工作線程中運(yùn)行的腳本一樣簡(jiǎn)單。
構(gòu)造函數(shù)
worker():創(chuàng)建一個(gè)專用的Web worker,在指定的URL上執(zhí)行腳本。示例:var?worker=new Worker('js/setTime.js');
屬性
onerror:
這是一個(gè)在error事件發(fā)生時(shí)調(diào)用的函數(shù),并且通過該函數(shù)冒泡worker。示例:worker.οnerrοr=function(){....};
onmessage:
? 這是一個(gè)worker中message事件要發(fā)生的時(shí)候調(diào)用的事件。? 示例:worker.onmessage=function(){....};
? 這個(gè)事件一般與postMessage事件同時(shí)使用,一個(gè)用來(lái)發(fā)送數(shù)據(jù),一個(gè)用來(lái)接受數(shù)據(jù)。例如:
?主線程中:
var jsId = "00001";var worker = new Worker('js/setTime.js');worker.postMessage(jsId);?
? ? ? ? ?worker線程中:
//接受事件參數(shù) onmessage = function(e) {console.log(e.data[0]) }這樣就完成了一個(gè)主線程向worker線程傳遞參數(shù)的過程。同樣如果worker線程要向主線程傳遞參數(shù)反過來(lái)寫即可。
?onmessageerror:
在消息傳遞過程出現(xiàn)錯(cuò)誤的屬性事件。示例:worker.onmessageerror=function(){....};
方法
postMessage:
向線程worker的內(nèi)部范圍發(fā)送消息,可以設(shè)置參數(shù),發(fā)送給worker線程的數(shù)據(jù)。在onmessage中接受。
terminate:
過多的開啟worker線程非常浪費(fèi)資源所以在使用過后可以終止它,終止方法使用terminate()。示例:worker.terminate();
close:
除了上面的關(guān)閉,如果是在worker線程自身也可以使用self.close()關(guān)閉。
?計(jì)時(shí)器示例
上面說(shuō)了那么多都是介紹worker的一些基本屬性或者方法的使用。下面通過具體的示例來(lái)看效果。
我們就拿最常用的倒計(jì)時(shí)來(lái)做示例說(shuō)明。很簡(jiǎn)單的一個(gè)例子。我們?cè)跇I(yè)務(wù)中經(jīng)常遇到倒計(jì)時(shí)業(yè)務(wù),在倒計(jì)時(shí)的時(shí)候還要做一些其他的業(yè)務(wù)。因?yàn)閖s單線程的特性,你會(huì)發(fā)現(xiàn)你的倒計(jì)時(shí)在你進(jìn)行其他業(yè)務(wù)操作的時(shí)候是暫停了的。例如現(xiàn)在是9:57你進(jìn)行了三秒的業(yè)務(wù)處理。等業(yè)務(wù)處理完成應(yīng)該是:9:54,但是你的倒計(jì)時(shí)還是9:57.就很明顯的說(shuō)明了這一個(gè)現(xiàn)象。
場(chǎng)景業(yè)務(wù)設(shè)計(jì)
那么我們現(xiàn)在設(shè)計(jì)這么一個(gè)業(yè)務(wù)操作,
- 首先我們頁(yè)面有一個(gè)定時(shí)器和一個(gè)業(yè)務(wù)操作按鈕(用來(lái)模擬耗時(shí)的操作)。
- 然后把定時(shí)器寫到一個(gè)worker中進(jìn)行倒計(jì)時(shí)操作。
- 最后通過消息通訊把每次的倒計(jì)時(shí)時(shí)間發(fā)送給主線程讓主線程修改顯示時(shí)間。
- 結(jié)束倒計(jì)時(shí)完畢結(jié)束定時(shí)器和線程
?有人可能會(huì)說(shuō)為什么還要回到主線程修改時(shí)間顯示值,請(qǐng)看一下上面的使用規(guī)則,我本來(lái)也是打算進(jìn)行主線程傳值dom給worker線程奈何不行只能在回傳回來(lái)。
代碼展示
?Html代碼:
<body><div><span id="Minute_p">10</span> :<span id="Second_p">00</span></div><button type="button" οnclick="business()">耗時(shí)操作</button></body>
主線程js代碼:
//頁(yè)面加載完成后初始化window.onload = function() {//創(chuàng)建定時(shí)器線程var worker = new Worker('js/setTime.js');//獲取dom對(duì)象var domMinute_p = document.getElementById('Minute_p');var domSecond_p = document.getElementById('Second_p');worker.postMessage(600);//這里可以接受worker線程的返回值worker.onmessage = function(event) {var totalSecond = event.data;console.log(totalSecond)//計(jì)算分鐘數(shù)var minute_p = parseInt(totalSecond / 60);domMinute_p.innerText = minute_p;//計(jì)算秒數(shù)var second_p = parseInt(totalSecond % 60);domSecond_p.innerText = second_p;}}//這里是模擬的耗時(shí)操作function business() {var data = [1, 2, 3, 4, 5];for(var i = 1; i < 1000; i++) {for(var j = 1; j < 1000; j++) {for(var k = 1; k < 5000; k++) {var b = k * 100;}}}console.log("業(yè)務(wù)終于走完了!")}worker線程js代碼:
var totalSecond = 600; var domMinute_p, domSecond_p,//接受事件參數(shù)onmessage = function(e) {console.log(e.data)domMinute_p = e.data;} var timeId = setInterval(function() {totalSecond--;if(totalSecond == 0) {self.close();}console.log(totalSecond)postMessage(totalSecond)}, 1000)好了大致示例就是這么多。下面是截圖效果:
?開始運(yùn)行后編號(hào)1會(huì)開始倒計(jì)時(shí),但是當(dāng)你點(diǎn)擊了編號(hào)2進(jìn)行了模擬耗時(shí)后,編號(hào)1還是會(huì)卡住,只有完成編號(hào)2后才會(huì)運(yùn)行,但是不同與上面說(shuō)到的單線程是,他再次運(yùn)行時(shí)的時(shí)間是正確時(shí)間,還是剛才的例子如果是9:57,點(diǎn)擊編號(hào)2模擬耗時(shí)了3秒,耗時(shí)完成后編號(hào)1會(huì)顯示9:54而不是單線程的9:57。就說(shuō)明worker現(xiàn)在在耗時(shí)操作的時(shí)候是持續(xù)運(yùn)行的,時(shí)間卡只不過是主線程的dom操作被卡住了而已(可以把耗時(shí)業(yè)務(wù)也開啟worker就不卡住了)。這里只是介紹worker的使用,所有就不糾結(jié)這個(gè)界面顯示的問題。
補(bǔ)充界面顯示方法:
后來(lái)有些人就問我怎弄界面顯示,我還是真的心疼你們啊,不知道舉一反三嗎,當(dāng)然是吧業(yè)務(wù)耗時(shí)也放到后臺(tái)線程啊,哈哈!!!
再特此說(shuō)明一個(gè)問題,僅在安卓測(cè)試:就是定時(shí)器在息屏模式下仍繼續(xù)執(zhí)行
我還是上面的例子做個(gè)例子:
把耗時(shí)業(yè)務(wù)放到business.js文件
onmessage = function(e) {console.log(e.data)for(var i = 1; i < 1000; i++) {for(var j = 1; j < 1000; j++) {for(var k = 1; k < 5000; k++) {var b = k * 100;}}}console.log("耗時(shí)業(yè)務(wù)走完了");postMessage(1) }然后主文件js調(diào)用就好了啊:
//這里是模擬的耗時(shí)操作 function business() {var worker = new Worker('js/business.js');worker.postMessage("開啟任務(wù)耗時(shí)");worker.onmessage = function(event) {if(event == 1) {console.log("點(diǎn)擊一次完成")worker.terminate()}}}截圖效果:
?
作者:YanBigFeg —— 顏秉鋒
出處:http://www.cnblogs.com/yanbigfeg
本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)標(biāo)明出處。如果您覺得本篇博文對(duì)您有所收獲,覺得小弟還算用心,請(qǐng)點(diǎn)擊右下角的 [推薦],謝謝!
總結(jié)
以上是生活随笔為你收集整理的【worker】js中的多线程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JSTL中fmt标签详解
- 下一篇: 关于线程执行顺序的问题