最新文章專題視頻專題問(wèn)答1問(wèn)答10問(wèn)答100問(wèn)答1000問(wèn)答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專題關(guān)鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問(wèn)答文章1 問(wèn)答文章501 問(wèn)答文章1001 問(wèn)答文章1501 問(wèn)答文章2001 問(wèn)答文章2501 問(wèn)答文章3001 問(wèn)答文章3501 問(wèn)答文章4001 問(wèn)答文章4501 問(wèn)答文章5001 問(wèn)答文章5501 問(wèn)答文章6001 問(wèn)答文章6501 問(wèn)答文章7001 問(wèn)答文章7501 問(wèn)答文章8001 問(wèn)答文章8501 問(wèn)答文章9001 問(wèn)答文章9501
當(dāng)前位置: 首頁(yè) - 科技 - 知識(shí)百科 - 正文

瀏覽器的多線程機(jī)制詳解

來(lái)源:懂視網(wǎng) 責(zé)編:小采 時(shí)間:2020-11-27 19:59:25
文檔

瀏覽器的多線程機(jī)制詳解

瀏覽器的多線程機(jī)制詳解:這次給大家?guī)?lái)瀏覽器的多線程機(jī)制詳解,瀏覽器的多線程機(jī)制使用的注意事項(xiàng)有哪些,下面就是實(shí)戰(zhàn)案例,一起來(lái)看一下。在講之前,大家都知道js是基于單線程的,而這個(gè)線程就是瀏覽器的js引擎。首先來(lái)看一下大家用的瀏覽器都具有那些線程吧。假如我們要執(zhí)行一些
推薦度:
導(dǎo)讀瀏覽器的多線程機(jī)制詳解:這次給大家?guī)?lái)瀏覽器的多線程機(jī)制詳解,瀏覽器的多線程機(jī)制使用的注意事項(xiàng)有哪些,下面就是實(shí)戰(zhàn)案例,一起來(lái)看一下。在講之前,大家都知道js是基于單線程的,而這個(gè)線程就是瀏覽器的js引擎。首先來(lái)看一下大家用的瀏覽器都具有那些線程吧。假如我們要執(zhí)行一些

認(rèn)為setTimeout中的問(wèn)候方法會(huì)立即被執(zhí)行,因?yàn)檫@并不是憑空而說(shuō),而是JavaScript API文檔明確定義第二個(gè)參數(shù)意義為隔多少毫秒后,回調(diào)方法就會(huì)被執(zhí)行. 這里設(shè)成0毫秒,理所當(dāng)然就立即被執(zhí)行了.
同理對(duì)setInterval的callbackFunction方法每間隔100毫秒就立即被執(zhí)行深信不疑!

但隨著JavaScript應(yīng)用開發(fā)經(jīng)驗(yàn)不斷的增加和豐富,有一天你發(fā)現(xiàn)了一段怪異的代碼而百思不得其解:

[javascript] view plain copy print?在CODE上查看代碼片派生到我的代碼片

  1. p.onclick = function(){

  2. setTimeout( function(){document.getElementById(’inputField’).focus();}, 0);

  3. };

既然是0毫秒后執(zhí)行,那么還用setTimeout干什么, 此刻, 堅(jiān)定的信念已開始動(dòng)搖.
直到最后某一天 , 你不小心寫了一段糟糕的代碼:

[javascript] view plain copy print?在CODE上查看代碼片派生到我的代碼片

  1. setTimeout( function(){ while(true){} } , 100);

  2. setTimeout( function(){ alert(’你好!’); } , 200);

  3. setInterval( callbackFunction , 200);

第一行代碼進(jìn)入了死循環(huán),但不久你就會(huì)發(fā)現(xiàn),第二,第三行并不是預(yù)料中的事情,alert問(wèn)候未見出現(xiàn),callbacKFunction也杳無(wú)音訊!

這時(shí)你徹底迷惘了,這種情景是難以接受的,因?yàn)楦淖冮L(zhǎng)久以來(lái)既定的認(rèn)知去接受新思想的過(guò)程是痛苦的,但情事實(shí)擺在眼前,對(duì)JavaScript真理的探求并不會(huì)因?yàn)橥纯喽V?下面讓我們來(lái)展開JavaScript線程和定時(shí)器探索之旅!

拔開云霧見月明

出現(xiàn)上面所有誤區(qū)的最主要一個(gè)原因是:潛意識(shí)中認(rèn)為,JavaScript引擎有多個(gè)線程在執(zhí)行,JavaScript的定時(shí)器回調(diào)函數(shù)是異步執(zhí)行的.

而事實(shí)上的,JavaScript使用了障眼法,在多數(shù)時(shí)候騙過(guò)了我們的眼睛,這里背光得澄清一個(gè)事實(shí):

JavaScript引擎是單線程運(yùn)行的,瀏覽器無(wú)論在什么時(shí)候都只且只有一個(gè)線程在運(yùn)行JavaScript程序.

JavaScript引擎用單線程運(yùn)行也是有意義的,單線程不必理會(huì)線程同步這些復(fù)雜的問(wèn)題,問(wèn)題得到簡(jiǎn)化.

那么單線程的JavaScript引擎是怎么配合瀏覽器內(nèi)核處理這些定時(shí)器和響應(yīng)瀏覽器事件的呢?
下面結(jié)合瀏覽器內(nèi)核處理方式簡(jiǎn)單說(shuō)明.

瀏覽器內(nèi)核實(shí)現(xiàn)允許多個(gè)線程異步執(zhí)行,這些線程在內(nèi)核制控下相互配合以保持同步.假如某一瀏覽器內(nèi)核的實(shí)現(xiàn)至少有三個(gè)常駐線程:javascript引擎線程,界面渲染線程,瀏覽器事件觸發(fā)線程,除些以外,也有一些執(zhí)行完就終止的線程,如Http請(qǐng)求線程,這些異步線程都會(huì)產(chǎn)生不同的異步事件,下面通過(guò)一個(gè)圖來(lái)闡明單線程的JavaScript引擎與另外那些線程是怎樣互動(dòng)通信的.雖然每個(gè)瀏覽器內(nèi)核實(shí)現(xiàn)細(xì)節(jié)不同,但這其中的調(diào)用原理都是大同小異.

由圖可看出,瀏覽器中的JavaScript引擎是基于事件驅(qū)動(dòng)的,這里的事件可看作是瀏覽器派給它的各種任務(wù),這些任務(wù)可以源自JavaScript引擎當(dāng)前執(zhí)行的代碼塊,如調(diào)用setTimeout添加一個(gè)任務(wù),也可來(lái)自瀏覽器內(nèi)核的其它線程,如界面元素鼠標(biāo)點(diǎn)擊事件,定時(shí)觸發(fā)器時(shí)間到達(dá)通知,異步請(qǐng)求狀態(tài)變更通知等.從代碼角度看來(lái)任務(wù)實(shí)體就是各種回調(diào)函數(shù),JavaScript引擎一直等待著任務(wù)隊(duì)列中任務(wù)的到來(lái).由于單線程關(guān)系,這些任務(wù)得進(jìn)行排隊(duì),一個(gè)接著一個(gè)被引擎處理.

上圖t1-t2..tn表示不同的時(shí)間點(diǎn),tn下面對(duì)應(yīng)的小方塊代表該時(shí)間點(diǎn)的任務(wù),假設(shè)現(xiàn)在是t1時(shí)刻,引擎運(yùn)行在t1對(duì)應(yīng)的任務(wù)方塊代碼內(nèi),在這個(gè)時(shí)間點(diǎn)內(nèi),我們來(lái)描述一下瀏覽器內(nèi)核其它線程的狀態(tài).

t1時(shí)刻:

GUI渲染線程:

該線程負(fù)責(zé)渲染瀏覽器界面HTML元素,當(dāng)界面需要重繪(Repaint)或由于某種操作引發(fā)回流(reflow)時(shí),該線程就會(huì)執(zhí)行.本文雖然重點(diǎn)解釋JavaScript定時(shí)機(jī)制,但這時(shí)有必要說(shuō)說(shuō)渲染線程,因?yàn)樵摼€程與JavaScript引擎線程是互斥的,這容易理解,因?yàn)镴avaScript腳本是可操縱DOM元素,在修改這些元素屬性同時(shí)渲染界面,那么渲染線程前后獲得的元素?cái)?shù)據(jù)就可能不一致了.

在JavaScript引擎運(yùn)行腳本期間,瀏覽器渲染線程都是處于掛起狀態(tài)的,也就是說(shuō)被”凍結(jié)”了.

所以,在腳本中執(zhí)行對(duì)界面進(jìn)行更新操作,如添加結(jié)點(diǎn),刪除結(jié)點(diǎn)或改變結(jié)點(diǎn)的外觀等更新并不會(huì)立即體現(xiàn)出來(lái),這些操作將保存在一個(gè)隊(duì)列中,待JavaScript引擎空閑時(shí)才有機(jī)會(huì)渲染出來(lái).

GUI事件觸發(fā)線程:

JavaScript腳本的執(zhí)行不影響html元素事件的觸發(fā),在t1時(shí)間段內(nèi),首先是用戶點(diǎn)擊了一個(gè)鼠標(biāo)鍵,點(diǎn)擊被瀏覽器事件觸發(fā)線程捕捉后形成一個(gè)鼠標(biāo)點(diǎn)擊事件,由圖可知,對(duì)于JavaScript引擎線程來(lái)說(shuō),這事件是由其它線程異步傳到任務(wù)隊(duì)列尾的,由于引擎正在處理t1時(shí)的任務(wù),這個(gè)鼠標(biāo)點(diǎn)擊事件正在等待處理.

定時(shí)觸發(fā)線程:

注意這里的瀏覽器模型定時(shí)計(jì)數(shù)器并不是由JavaScript引擎計(jì)數(shù)的,因?yàn)镴avaScript引擎是單線程的,如果處于阻塞線程狀態(tài)就計(jì)不了時(shí),它必須依賴外部來(lái)計(jì)時(shí)并觸發(fā)定時(shí),所以隊(duì)列中的定時(shí)事件也是異步事件.

由圖可知,在這t1的時(shí)間段內(nèi),繼鼠標(biāo)點(diǎn)擊事件觸發(fā)后,先前已設(shè)置的setTimeout定時(shí)也到達(dá)了,此刻對(duì)JavaScript引擎來(lái)說(shuō),定時(shí)觸發(fā)線程產(chǎn)生了一個(gè)異步定時(shí)事件并放到任務(wù)隊(duì)列中, 該事件被排到點(diǎn)擊事件回調(diào)之后,等待處理.
同理, 還是在t1時(shí)間段內(nèi),接下來(lái)某個(gè)setInterval定時(shí)器也被添加了,由于是間隔定時(shí),在t1段內(nèi)連續(xù)被觸發(fā)了兩次,這兩個(gè)事件被排到隊(duì)尾等待處理.

可見,假如時(shí)間段t1非常長(zhǎng),遠(yuǎn)大于setInterval的定時(shí)間隔,那么定時(shí)觸發(fā)線程就會(huì)源源不斷的產(chǎn)生異步定時(shí)事件并放到任務(wù)隊(duì)列尾而不管它們是否已被處理,但一旦t1和最先的定時(shí)事件前面的任務(wù)已處理完,這些排列中的定時(shí)事件就依次不間斷的被執(zhí)行,這是因?yàn)?對(duì)于JavaScript引擎來(lái)說(shuō),在處理隊(duì)列中的各任務(wù)處理方式都是一樣的,只是處理的次序不同而已.

t1過(guò)后,也就是說(shuō)當(dāng)前處理的任務(wù)已返回,JavaScript引擎會(huì)檢查任務(wù)隊(duì)列,發(fā)現(xiàn)當(dāng)前隊(duì)列非空,就取出t2下面對(duì)應(yīng)的任務(wù)執(zhí)行,其它時(shí)間依此類推,由此看來(lái):

如果隊(duì)列非空,引擎就從隊(duì)列頭取出一個(gè)任務(wù),直到該任務(wù)處理完,即返回后引擎接著運(yùn)行下一個(gè)任務(wù),在任務(wù)沒返回前隊(duì)列中的其它任務(wù)是沒法被執(zhí)行的.

相信您現(xiàn)在已經(jīng)很清楚JavaScript是否可多線程,也了解理解JavaScript定時(shí)器運(yùn)行機(jī)制了,下面我們來(lái)對(duì)一些案例進(jìn)行分析:

案例1:setTimeout與setInterval

[javascript] view plain copy print?在CODE上查看代碼片派生到我的代碼片

  1. setTimeout(function(){

  2. /* 代碼塊... */

  3. setTimeout(arguments.callee, 10);

  4. }, 10);

  5. setInterval(function(){

  6. /*代碼塊... */

  7. }, 10);

這兩段代碼看一起效果一樣,其實(shí)非也,第一段中回調(diào)函數(shù)內(nèi)的setTimeout是JavaScript引擎執(zhí)行后再設(shè)置新的setTimeout定時(shí), 假定上一個(gè)回調(diào)處理完到下一個(gè)回調(diào)開始處理為一個(gè)時(shí)間間隔,理論兩個(gè)setTimeout回調(diào)執(zhí)行時(shí)間間隔>=10ms.第二段自setInterval設(shè)置定時(shí)后,定時(shí)觸發(fā)線程就會(huì)源源不斷的每隔十秒產(chǎn)生異步定時(shí)事件并放到任務(wù)隊(duì)列尾,理論上兩個(gè)setInterval回調(diào)執(zhí)行時(shí)間間隔<=10.

案例2:ajax異步請(qǐng)求是否真的異步?

很多同學(xué)朋友搞不清楚,既然說(shuō)JavaScript是單線程運(yùn)行的,那么XMLHttpRequest在連接后是否真的異步?
其實(shí)請(qǐng)求確實(shí)是異步的,不過(guò)這請(qǐng)求是由瀏覽器新開一個(gè)線程請(qǐng)求(參見上圖),當(dāng)請(qǐng)求的狀態(tài)變更時(shí),如果先前已設(shè)置回調(diào),這異步線程就產(chǎn)生狀態(tài)變更事件放到JavaScript引擎的處理隊(duì)列中等待處理,當(dāng)任務(wù)被處理時(shí),JavaScript引擎始終是單線程運(yùn)行回調(diào)函數(shù),具體點(diǎn)即還是單線程運(yùn)行onreadystatechange所設(shè)置的函數(shù).

相信看了本文案例你已經(jīng)掌握了方法,更多精彩請(qǐng)關(guān)注Gxl網(wǎng)其它相關(guān)文章!

推薦閱讀:

單線程JS與多線程瀏覽器的使用

關(guān)于js中類型轉(zhuǎn)換的一些小問(wèn)題

JS中的顯示類型轉(zhuǎn)換

js怎樣實(shí)現(xiàn)橫向滾動(dòng)與浮動(dòng)導(dǎo)航

聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文檔

瀏覽器的多線程機(jī)制詳解

瀏覽器的多線程機(jī)制詳解:這次給大家?guī)?lái)瀏覽器的多線程機(jī)制詳解,瀏覽器的多線程機(jī)制使用的注意事項(xiàng)有哪些,下面就是實(shí)戰(zhàn)案例,一起來(lái)看一下。在講之前,大家都知道js是基于單線程的,而這個(gè)線程就是瀏覽器的js引擎。首先來(lái)看一下大家用的瀏覽器都具有那些線程吧。假如我們要執(zhí)行一些
推薦度:
標(biāo)簽: 瀏覽器 解析 瀏覽器的
  • 熱門焦點(diǎn)

最新推薦

猜你喜歡

熱門推薦

專題
Top