Web Worker

Javascript運(yùn)行在單線程環(huán)境中款咖,雖然單線程避免了多線程的難點(diǎn),但缺點(diǎn)也很明顯奄喂,如果某個任務(wù)耗時很久铐殃,就無法處理其他任務(wù),會讓用戶感覺瀏覽器卡住了跨新。所以瀏覽器中除了JS引擎線程富腊,還有其他線程,比如 GUI 渲染線程域帐、http 請求線程赘被、事件觸發(fā)線程等,而通過事件循環(huán)機(jī)制對setTimeout/setInterval肖揣、ajax和dom事件的異步處理民假,就需要多個線程的參與。
HTML5引進(jìn)了 Web Worker龙优,可讓JS在后臺運(yùn)行羊异,執(zhí)行耗時長的任務(wù),而不影響主頁面代碼的執(zhí)行。
1.定義:Web Worker 是HTML5標(biāo)準(zhǔn)的一部分球化,允許一段JavaScript程序運(yùn)行在主線程之外的另外一個線程中秽晚。Web Worker 規(guī)范中定義了兩類工作線程,分別是專用線程Dedicated Worker和共享線程 Shared Worker筒愚,其中赴蝇,Dedicated Worker只能為一個頁面所使用,而Shared Worker可以被多個頁面所共享巢掺,本文以前者為例句伶。
2.示例:
主頁面代碼 main.js

 // 一個較大的數(shù)組,其元素由隨機(jī)數(shù)構(gòu)成陆淀,傳到worker中去異步處理
    let arr=[]
    for(let i=0;i<1000000;i++){
        let item=Math.round(Math.random()*100);
        arr.push(item);
    }

    // 這行代碼會導(dǎo)致瀏覽器加載(下載)worker.js文件考余,但不會立即執(zhí)行
    let worker=new Worker('./worker.js')

    // 收到 worker 的返回結(jié)果
    worker.onmessage=function (event) {
        let data=event.data;
        console.log(data);
        worker.terminate();//終止worker的執(zhí)行
    }
    // worker內(nèi)部js執(zhí)行出錯
    worker.onerror=function (event) {
        console.log(`Error ${event.filename } in line ${event.lineno}: ${event.message}`);
    }

    // 只有給worker傳遞消息后,它才會執(zhí)行相應(yīng)文件中的代碼
    // 而且數(shù)據(jù)會以異步方式被傳遞給worker
    worker.postMessage(arr);

在主頁面main.js代碼中轧苫,實(shí)例化 Worker 對象并傳入要執(zhí)行的 JS 文件名楚堤,這一對象可視為主線程中對新創(chuàng)建的工作線程的引用。然后調(diào)用worker.postMessage()方法含懊,給新創(chuàng)建的工作線程傳遞消息身冬,消息內(nèi)容可以是任何可被序列化的值(一般而言,能夠被序列化為 JSON 結(jié)構(gòu)的任何值都可作為參數(shù)被傳遞給 postMessage岔乔。而且傳入的值是復(fù)制到 worker中酥筝,而不是直接傳過去,即在 worker 中對傳入值的處理雏门,不會影響主頁面中的原始值)嘿歌。
worker 是通過messageerror與主頁面通信的,在主頁面中分別定義 onmessage事件和onerror事件的回調(diào)處理函數(shù)茁影,當(dāng)woker線程返回數(shù)據(jù)時宙帝,onmessage回調(diào)函數(shù)執(zhí)行,數(shù)據(jù)封裝在event參數(shù)的data屬性中募闲。任何時候調(diào)用 worker 的 terminate()方法會立即終止worker中代碼執(zhí)行(后續(xù)過程不再發(fā)生茄唐,包括 message 和 error 事件也不會被觸發(fā));當(dāng)worker線程執(zhí)行出錯時(只要 worker 內(nèi)部的 JS 在執(zhí)行過程中遇到錯誤)蝇更,onerror回調(diào)函數(shù)執(zhí)行,event參數(shù)中封裝了錯誤對象的文件名呼盆、出錯行號和具體錯誤信息年扩。

Dedicated Worker所執(zhí)行的代碼worker.js,例如是計(jì)算量較大的 js 處理访圃。

self.onmessage=function (event) {
    let data=event.data.sort((v1,v2)=>v1-v2);
    self.postMessage(data);
    self.close();//停止工作
}

在worker.js代碼中厨幻,定義了onmessage事件處理函數(shù),由主線程傳入的數(shù)據(jù),封裝在event.data中况脆,數(shù)據(jù)處理完成后饭宾,通過postMessage方法完成與主線程通信。在工作線程代碼中格了,onmessage事件和postMessage方法在其全局作用域可以訪問看铆。在 Worker 內(nèi)部,可以調(diào)用 close() 方法停止工作盛末,效果和在主頁面中調(diào)用 terminate() 方法一樣弹惦。

3. Worker全局作用域
Web Worker 所執(zhí)行的 JS 代碼完全在另一個作用域中,與主頁面中的代碼不共享作用域(在上文例子中悄但,main.js 和 worker.js 中的代碼作用域互相獨(dú)立)棠隐。在 Web Worker中,同樣有一個全局對象以及其他對象和方法檐嚣,但是 Web Worker 中的代碼不能訪問 dom助泽,也無法影響頁面外觀。
Web Worker中的全局對象就是 worker 對象本身(注意嚎京,與主頁面 mian.js 中的 worker 不是同一個對象)嗡贺,即在這個特殊的全局作用域里,this 和 self 指向的都是 worker 對象挖藏。Web Worker 本身就是一個最小化的運(yùn)行環(huán)境暑刃。
在Web Worker中,可以獲得下列對象膜眠、方法
(1)navigator對象
(2)location對象岩臣,只讀
(3)XMLHttpRequest對象
(4)setTimeout/setInterval方法
(5)Application Cache
(6)通過importScripts()方法加載其他腳本
(7)創(chuàng)建新的Web Worker
但不能獲得下列對象
(1)DOM對象
(2)window對象
(3)document對象
(4)parent對象
上述的規(guī)范,限制了在worker線程中獲得主線程頁面相關(guān)對象的能力宵膨,所以在worker線程中架谎,不能訪問dom元素,避免出現(xiàn)混亂的 dom 操作辟躏。

4. Worker線程執(zhí)行流程
webKit加載并執(zhí)行worker線程的流程如下圖所示

Worker線程執(zhí)行流程

解釋:
(1)worker線程的創(chuàng)建的是異步的
代碼執(zhí)行到"var worker = new Worker(task.js')“時谷扣,在內(nèi)核中構(gòu)造WebCore::JSWorker對象(JSBbindings層)以及對應(yīng)的WebCore::Worker對象(WebCore模塊),根據(jù)初始化的url地址"task.js"發(fā)起異步加載的流程捎琐;主線程代碼不會阻塞在這里等待worker線程去加載会涎、執(zhí)行指定的腳本文件,而是會立即向下繼續(xù)執(zhí)行后面代碼瑞凑。
(2)postMessage消息交互由內(nèi)核調(diào)度
main.js中末秃,在創(chuàng)建woker線程后,立即調(diào)用了postMessage方法傳遞了數(shù)據(jù)籽御,在worker線程還沒創(chuàng)建完成時蹋岩,main.js中發(fā)出的消息,會先存儲在一個臨時消息隊(duì)列中铛铁,當(dāng)異步創(chuàng)建worker線程完成,臨時消息隊(duì)列中的消息數(shù)據(jù)復(fù)制到woker對應(yīng)的WorkerRunLoop的消息隊(duì)列中项鬼,worker線程開始處理消息。在經(jīng)過一輪消息來回后劲阎,繼續(xù)通信時绘盟, 這個時候因?yàn)閣orker線程已經(jīng)創(chuàng)建,所以消息會直接添加到WorkerRunLoop的消息隊(duì)列中哪工;

5. Worker線程數(shù)據(jù)通訊方式
主線程與子線程數(shù)據(jù)通信方式有多種奥此,通信內(nèi)容,可以是文本雁比,也可以是對象稚虎。需要注意的是,這種通信是拷貝關(guān)系偎捎,即是傳值而不是地址蠢终,子線程對通信內(nèi)容的修改,不會影響到主線程茴她。事實(shí)上寻拂,瀏覽器內(nèi)部的運(yùn)行機(jī)制是,先將通信內(nèi)容串行化丈牢,然后把串行化后的字符串發(fā)給子線程祭钉,后者再將它還原。
主線程與子線程之間也可以交換二進(jìn)制數(shù)據(jù)己沛,比如File慌核、Blob、ArrayBuffer等對象申尼,也可以在線程之間發(fā)送垮卓。但是,用拷貝方式發(fā)送二進(jìn)制數(shù)據(jù)师幕,會造成性能問題粟按。比如,主線程向子線程發(fā)送一個50MB文件霹粥,默認(rèn)情況下瀏覽器會生成一個原文件的拷貝灭将。為了解決這個問題,JavaScript允許主線程把二進(jìn)制數(shù)據(jù)直接轉(zhuǎn)移給子線程后控,轉(zhuǎn)移后主線程無法再使用這些數(shù)據(jù)宗侦,這是為了防止出現(xiàn)多個線程同時修改數(shù)據(jù)的問題,這種轉(zhuǎn)移數(shù)據(jù)的方法忆蚀,叫做Transferable Objects矾利。

// Create a 32MB "file" and fill it.
let uInt8Array = new Uint8Array(1024*1024*32); // 32MB
for (let i = 0,len=uInt8Array .length ; i <len ; ++i) {
    uInt8Array[i] = i;
}
worker.postMessage(uInt8Array.buffer, [uInt8Array.buffer]);

6. Web Worker作用
Web Worker并沒有為Javascript帶來多線程編程能力,JS 代碼的執(zhí)行仍然是單線程的馋袜。Web Worker帶來的是后臺計(jì)算能力男旗。
Web Worker自身是由webkit多線程實(shí)現(xiàn),但它并沒有為Javasctipt語言帶來多線程編程特性欣鳖,我們現(xiàn)在仍然不能在Javascript代碼中創(chuàng)建并管理一個線程察皇,或者主動控制線程間的同步與鎖等特性。
在我看來泽台,Web Worker可以說是worker編程模型在瀏覽器端Javascript語言中的應(yīng)用什荣。瀏覽器的運(yùn)行時,同其他GUI程序類似,核心邏輯像是下面這個無限循環(huán):

while(true){  
    1 處理數(shù)據(jù)和更新對象狀態(tài)  
    2 渲染可視化UI  
}

在Web Worker之前怀酷,Javascript執(zhí)行引擎只能在一個單線程環(huán)境中完成這兩項(xiàng)任務(wù)稻爬。Web Worker的引入,是借鑒了worker編程模型蜕依,給單線程的Javascript帶來了后臺計(jì)算的能力桅锄。
既然Web Worker為瀏覽器端Javascript帶來了后臺計(jì)算能力,我們便可利用這一能力样眠,將無限循環(huán)中第一項(xiàng)“處理數(shù)據(jù)和更新對象狀態(tài) ”的耗時部分交由Web Worker執(zhí)行友瘤,提升頁面性能。
部分典型的應(yīng)用場景如下:
(1)使用專用線程進(jìn)行數(shù)學(xué)運(yùn)算
Web Worker最簡單的應(yīng)用就是用來做后臺計(jì)算檐束,而這種計(jì)算并不會中斷主頁面的代碼執(zhí)行辫秧。
(2)圖像處理
通過使用從<canvas>或者<video>元素中獲取的數(shù)據(jù),可以把圖像分割成幾個不同的區(qū)域并且把它們推送給并行的不同Workers來做計(jì)算(如將彩色圖像轉(zhuǎn)換成灰階圖像)被丧。
(3)大量數(shù)據(jù)的檢索
當(dāng)需要在調(diào)用 ajax后處理大量的數(shù)據(jù)盟戏,如果處理這些數(shù)據(jù)所需的時間長短非常重要,可以在Web Worker中來做這些晚碾,避免凍結(jié)UI線程抓半。

reference
1.The Basics of Web Workers
http://www.html5rocks.com/en/tutorials/workers/basics/

  1. 深入 HTML5 Web Worker 應(yīng)用實(shí)踐:多線程編程
    http://www.ibm.com/developerworks/cn/web/1112_sunch_webworker/index.html
  2. JavaScript 工作線程實(shí)現(xiàn)方式
    http://www.ibm.com/developerworks/cn/web/1105_chengfu_jsworker/index.html

4.HTML5 與 ”性工能“障礙
http://fins.iteye.com/blog/1747321

5.Web Worker在WebKit中的實(shí)現(xiàn)機(jī)制
http://blog.csdn.net/codigger/article/details/40581343

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市格嘁,隨后出現(xiàn)的幾起案子笛求,更是在濱河造成了極大的恐慌,老刑警劉巖糕簿,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件探入,死亡現(xiàn)場離奇詭異,居然都是意外死亡懂诗,警方通過查閱死者的電腦和手機(jī)蜂嗽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來殃恒,“玉大人植旧,你說我怎么就攤上這事辱揭。” “怎么了病附?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵问窃,是天一觀的道長。 經(jīng)常有香客問我完沪,道長域庇,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任覆积,我火速辦了婚禮听皿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘宽档。我一直安慰自己尉姨,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布雌贱。 她就那樣靜靜地躺著啊送,像睡著了一般。 火紅的嫁衣襯著肌膚如雪欣孤。 梳的紋絲不亂的頭發(fā)上馋没,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天,我揣著相機(jī)與錄音降传,去河邊找鬼篷朵。 笑死,一個胖子當(dāng)著我的面吹牛婆排,可吹牛的內(nèi)容都是我干的声旺。 我是一名探鬼主播,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼段只,長吁一口氣:“原來是場噩夢啊……” “哼腮猖!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起赞枕,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤澈缺,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后炕婶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體姐赡,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年柠掂,在試婚紗的時候發(fā)現(xiàn)自己被綠了项滑。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡涯贞,死狀恐怖枪狂,靈堂內(nèi)的尸體忽然破棺而出危喉,到底是詐尸還是另有隱情,我是刑警寧澤摘完,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布姥饰,位于F島的核電站,受9級特大地震影響孝治,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜审磁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一谈飒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧态蒂,春花似錦杭措、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至瘩蚪,卻和暖如春泉懦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背疹瘦。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工崩哩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人言沐。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓邓嘹,卻偏偏與公主長得像,于是被迫代替她去往敵國和親险胰。 傳聞我的和親對象是個殘疾皇子汹押,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評論 2 355