摘要:是的,沒(méi)錯(cuò)是單線程的,但是會(huì)另開(kāi)一個(gè)線程,這個(gè)線程依賴于某個(gè)計(jì)時(shí)裝置,這時(shí),其實(shí)是不管而繼續(xù)往下進(jìn)行的,而也是獨(dú)立的線程計(jì)時(shí)的。
setTimeout的運(yùn)行機(jī)制
先看下面一個(gè)例子:
這個(gè)代碼會(huì)讓瀏覽器陷入崩潰,為什么?
其實(shí):
當(dāng)javascript運(yùn)行時(shí)遇到setTimeout后其實(shí)會(huì)另開(kāi)一條線程(剛剛不是說(shuō)javascript是單線程的嘛?)。是的,沒(méi)錯(cuò)javascript是單線程的,但是setTimeout會(huì)另開(kāi)一個(gè)線程,這個(gè)線程依賴于某個(gè)計(jì)時(shí)裝置,這時(shí),javascript其實(shí)是不管setTimeout而繼續(xù)往下進(jìn)行的,而setTimeout也是獨(dú)立的線程計(jì)時(shí)的。而javascript在運(yùn)行完全部的代碼后會(huì)回過(guò)頭來(lái)重新檢測(cè)自己的隊(duì)列中有沒(méi)待執(zhí)行的命令或者函數(shù),如果有就執(zhí)行,沒(méi)有就等待。直到有待執(zhí)行的命令被加載進(jìn)這個(gè)隊(duì)列中然后執(zhí)行。在這期間,setTimeout依賴的那個(gè)計(jì)時(shí)線程如果時(shí)間到了,那么它會(huì)把setTimeout中要執(zhí)行的函數(shù)或者命令傳送到j(luò)avascript的等待隊(duì)列中,等待javascript執(zhí)行完命令后回頭來(lái)檢測(cè)等待隊(duì)列中未執(zhí)行的函數(shù)或命令。
所以,在這里案例中,首先t變成true,然后javascript往下執(zhí)行,遇到了setTimeout,這時(shí)setTimeout啟用了另一個(gè)計(jì)時(shí)線程。此時(shí)javascript不管它跳過(guò)(因?yàn)樗闪硪粋€(gè)線程來(lái)控制)。然后遇到了while(t)這個(gè)循環(huán),因?yàn)榍懊姘裻設(shè)置成了真,所以這個(gè)循環(huán)一直成立,所以也就一直循環(huán)下去。javascript的線程一直結(jié)束不了,所以無(wú)法回來(lái)檢查等待隊(duì)列,根本不會(huì)執(zhí)行setTimeout中代碼。所以t永遠(yuǎn)也無(wú)法變成假,而javascript也永遠(yuǎn)無(wú)法停止。
了解了setTimeout的運(yùn)行機(jī)制后 我們來(lái)看看幾個(gè)setTimeout并列運(yùn)行 它們的執(zhí)行順序由什么決定
setTimeout(function(){ console.log(3); },5000); setTimeout(function(){ console.log(5); },3000); setTimeout(function(){ console.log(6); },14000);
結(jié)果是5,3,6。幾個(gè)都是setTimeout,因此都會(huì)放到等待隊(duì)列~~~
而這些隊(duì)列里的函數(shù)誰(shuí)先執(zhí)行呢?就是根據(jù)setTimeout里的第二個(gè)參數(shù)(延遲時(shí)間)決定的。
再看看一個(gè)復(fù)雜的例子 如果setTimeout中嵌套了setTimeout 呢?
var d=[]; d[0]=function(){setTimeout(function(){console.log(3);setTimeout(function(){console.log(4)})})}; d[1]=function(){setTimeout(function(){console.log(5);setTimeout(function(){console.log(6)},0)},100)}; for(var i=0;i<2;i++){d[i]();}
這段代碼 按順序打印的是 3,4,5,6 實(shí)際上是這樣 主程序執(zhí)行完后 遇到了兩個(gè)settimeout函數(shù) 第一個(gè)是0毫秒,第二是100毫秒 先執(zhí)行第一個(gè)settimeout,打印出3,
第一個(gè)函數(shù)執(zhí)行的時(shí)候又遇見(jiàn)了一個(gè)settimeout 加入隊(duì)列 等待時(shí)間是0,打印出了4,登到了100毫秒后 第二個(gè)settimeout被執(zhí)行 打印出5.又遇見(jiàn)一個(gè)settimeout,同樣被加入隊(duì)列 等了0毫秒 被執(zhí)行
再換換數(shù)據(jù)試一試:
var d=[];d[0]=function(){setTimeout(function(){console.log(3);setTimeout(function(){console.log(4)})})}; d[1]=function(){setTimeout(function(){console.log(5);setTimeout(function(){console.log(6)})},2)}; for(var i=0;i<2;i++){d[i]();}
這里的時(shí)間相差極短 打印出的順序是3,5,4,6
如果再換一下數(shù)據(jù):
var d=[];d[0]=function(){setTimeout(function(){console.log(3);setTimeout(function(){console.log(4)})})}; d[1]=function(){setTimeout(function(){console.log(5);setTimeout(function(){console.log(6)})},4)}; for(var i=0;i<2;i++){d[i]();}
這里相比上面的案例只是改了一個(gè)數(shù)字 2毫秒改成了4毫秒 執(zhí)行順序變成 3,4,5,6
為什么?
因?yàn)樯厦娴陌咐龍?zhí)行完第一個(gè)settimeout之后 過(guò)了2毫秒了 超過(guò)了第二個(gè)函數(shù)的等待時(shí)間 會(huì)立即執(zhí)行第二個(gè)settimeout。如果等待時(shí)間過(guò)大 就不會(huì)這樣了
總之,只需記住一點(diǎn):延遲時(shí)間始終是相對(duì)主程序執(zhí)行完畢的那個(gè)時(shí)間算的 ,并且多個(gè)setTimeout的先后順序也是由這個(gè)延遲時(shí)間決定的,如果遇到某個(gè)setTimeout需要花費(fèi)大量的時(shí)間怎么辦?可由于js是單線程,所以當(dāng)執(zhí)行到這個(gè)setTimeout后,會(huì)將這個(gè)程序執(zhí)行完成后再去執(zhí)行下一個(gè)setTimeout,無(wú)論下一個(gè)setTimeout的延遲時(shí)間為多少,如果這兩個(gè)setTimeout時(shí)間的差值小于第一個(gè)setTimeout消耗的時(shí)間,程序會(huì)等待這個(gè)setTimeout執(zhí)行完成后立即執(zhí)行下一個(gè)setTimeout,如果差值大于消耗的時(shí)間,就按照和主程序約定的延遲(setTimeout里的第二個(gè)參數(shù))執(zhí)行即可
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/84331.html
摘要:如果對(duì)語(yǔ)法分析和預(yù)編譯,還有疑問(wèn)引擎執(zhí)行的過(guò)程的理解語(yǔ)法分析和預(yù)編譯階段。參與執(zhí)行過(guò)程的線程分別是引擎線程也稱為內(nèi)核,負(fù)責(zé)解析執(zhí)行腳本程序的主線程例如引擎。以上便是引擎執(zhí)行宏任務(wù)的整個(gè)過(guò)程。 一、概述 js引擎執(zhí)行過(guò)程主要分為三個(gè)階段,分別是語(yǔ)法分析,預(yù)編譯和執(zhí)行階段,上篇文章我們介紹了語(yǔ)法分析和預(yù)編譯階段,那么我們先做個(gè)簡(jiǎn)單概括,如下: 1、語(yǔ)法分析: 分別對(duì)加載完成的代碼塊進(jìn)行語(yǔ)法...
摘要:如果對(duì)語(yǔ)法分析和預(yù)編譯,還有疑問(wèn)引擎執(zhí)行的過(guò)程的理解語(yǔ)法分析和預(yù)編譯階段。參與執(zhí)行過(guò)程的線程分別是引擎線程也稱為內(nèi)核,負(fù)責(zé)解析執(zhí)行腳本程序的主線程例如引擎。以上便是引擎執(zhí)行宏任務(wù)的整個(gè)過(guò)程。一、概述 js引擎執(zhí)行過(guò)程主要分為三個(gè)階段,分別是語(yǔ)法分析,預(yù)編譯和執(zhí)行階段,上篇文章我們介紹了語(yǔ)法分析和預(yù)編譯階段,那么我們先做個(gè)簡(jiǎn)單概括,如下: 1、語(yǔ)法分析: 分別對(duì)加載完成的代碼塊進(jìn)行語(yǔ)法檢驗(yàn),語(yǔ)...
摘要:曾經(jīng)的理解首先,是單線程語(yǔ)言,也就意味著同一個(gè)時(shí)間只能做一件事,那么為什么不是多線程呢這樣還能提高效率啊假定同時(shí)有兩個(gè)線程,一個(gè)線程在某個(gè)節(jié)點(diǎn)上編輯了內(nèi)容,而另一個(gè)線程刪除了這個(gè)節(jié)點(diǎn),這時(shí)瀏覽器就很懵逼了,到底以執(zhí)行哪個(gè)操作呢所以,設(shè)計(jì)者把 Event Loop曾經(jīng)的理解 首先,JS是單線程語(yǔ)言,也就意味著同一個(gè)時(shí)間只能做一件事,那么 為什么JavaScript不是多線程呢?這樣還能提...
摘要:一個(gè)頁(yè)面在瀏覽器顯示出來(lái)至少需要個(gè)線程,分別是引擎,渲染,事件觸發(fā)。其中事件觸發(fā)是獨(dú)立于其他個(gè)執(zhí)行的,而和是相互排斥的,也就是說(shuō)同一個(gè)時(shí)間二者只有一個(gè)在工作。 作為DOM本身十分重要的2個(gè)異步執(zhí)行函數(shù),初學(xué)者感覺(jué)這個(gè)很不好理解,我簡(jiǎn)單寫(xiě)一寫(xiě)我的理解 setTimeout (func, millisec); setInterval(func, millisec); 這兩個(gè)方法在形式看起來(lái)...
摘要:所以其實(shí)和所謂的異步調(diào)用事實(shí)上是通過(guò)將代碼段插入到代碼的執(zhí)行隊(duì)列中實(shí)現(xiàn)的。當(dāng)執(zhí)行和的時(shí)候,會(huì)根據(jù)你設(shè)定的時(shí)間準(zhǔn)確地找到代碼的插入點(diǎn)。綜上所述,其實(shí)終歸是單線程產(chǎn)物。無(wú)論如何異步都不可能突破單線程這個(gè)障礙。 發(fā)表過(guò)一片博客《跟著我用JavaScript寫(xiě)計(jì)時(shí)器》,比較基礎(chǔ).....有網(wǎng)友說(shuō)應(yīng)該寫(xiě)一下setTimeout的原理和機(jī)制,嗯,今天就來(lái)寫(xiě)一下吧: 直奔主題:setTimeout和...
閱讀 3313·2023-04-26 00:58
閱讀 1268·2021-09-22 16:04
閱讀 3311·2021-09-02 15:11
閱讀 1554·2019-08-30 15:55
閱讀 2339·2019-08-30 15:55
閱讀 3248·2019-08-23 18:41
閱讀 3458·2019-08-23 18:18
閱讀 2752·2019-08-23 17:53