摘要:是的,沒錯(cuò)是單線程的,但是會(huì)另開一個(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ì)另開一條線程(剛剛不是說javascript是單線程的嘛?)。是的,沒錯(cuò)javascript是單線程的,但是setTimeout會(huì)另開一個(gè)線程,這個(gè)線程依賴于某個(gè)計(jì)時(shí)裝置,這時(shí),javascript其實(shí)是不管setTimeout而繼續(xù)往下進(jìn)行的,而setTimeout也是獨(dú)立的線程計(jì)時(shí)的。而javascript在運(yùn)行完全部的代碼后會(huì)回過頭來重新檢測(cè)自己的隊(duì)列中有沒待執(zhí)行的命令或者函數(shù),如果有就執(zhí)行,沒有就等待。直到有待執(zhí)行的命令被加載進(jìn)這個(gè)隊(duì)列中然后執(zhí)行。在這期間,setTimeout依賴的那個(gè)計(jì)時(shí)線程如果時(shí)間到了,那么它會(huì)把setTimeout中要執(zhí)行的函數(shù)或者命令傳送到j(luò)avascript的等待隊(duì)列中,等待javascript執(zhí)行完命令后回頭來檢測(cè)等待隊(duì)列中未執(zhí)行的函數(shù)或命令。
所以,在這里案例中,首先t變成true,然后javascript往下執(zhí)行,遇到了setTimeout,這時(shí)setTimeout啟用了另一個(gè)計(jì)時(shí)線程。此時(shí)javascript不管它跳過(因?yàn)樗闪硪粋€(gè)線程來控制)。然后遇到了while(t)這個(gè)循環(huán),因?yàn)榍懊姘裻設(shè)置成了真,所以這個(gè)循環(huán)一直成立,所以也就一直循環(huán)下去。javascript的線程一直結(jié)束不了,所以無法回來檢查等待隊(duì)列,根本不會(huì)執(zhí)行setTimeout中代碼。所以t永遠(yuǎn)也無法變成假,而javascript也永遠(yuǎn)無法停止。
了解了setTimeout的運(yùn)行機(jī)制后 我們來看看幾個(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ù)誰先執(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í)候又遇見了一個(gè)settimeout 加入隊(duì)列 等待時(shí)間是0,打印出了4,登到了100毫秒后 第二個(gè)settimeout被執(zhí)行 打印出5.又遇見一個(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之后 過了2毫秒了 超過了第二個(gè)函數(shù)的等待時(shí)間 會(huì)立即執(zhí)行第二個(gè)settimeout。如果等待時(shí)間過大 就不會(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,無論下一個(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://systransis.cn/yun/84331.html
摘要:如果對(duì)語法分析和預(yù)編譯,還有疑問引擎執(zhí)行的過程的理解語法分析和預(yù)編譯階段。參與執(zhí)行過程的線程分別是引擎線程也稱為內(nèi)核,負(fù)責(zé)解析執(zhí)行腳本程序的主線程例如引擎。以上便是引擎執(zhí)行宏任務(wù)的整個(gè)過程。 一、概述 js引擎執(zhí)行過程主要分為三個(gè)階段,分別是語法分析,預(yù)編譯和執(zhí)行階段,上篇文章我們介紹了語法分析和預(yù)編譯階段,那么我們先做個(gè)簡單概括,如下: 1、語法分析: 分別對(duì)加載完成的代碼塊進(jìn)行語法...
摘要:如果對(duì)語法分析和預(yù)編譯,還有疑問引擎執(zhí)行的過程的理解語法分析和預(yù)編譯階段。參與執(zhí)行過程的線程分別是引擎線程也稱為內(nèi)核,負(fù)責(zé)解析執(zhí)行腳本程序的主線程例如引擎。以上便是引擎執(zhí)行宏任務(wù)的整個(gè)過程。一、概述 js引擎執(zhí)行過程主要分為三個(gè)階段,分別是語法分析,預(yù)編譯和執(zhí)行階段,上篇文章我們介紹了語法分析和預(yù)編譯階段,那么我們先做個(gè)簡單概括,如下: 1、語法分析: 分別對(duì)加載完成的代碼塊進(jìn)行語法檢驗(yàn),語...
摘要:曾經(jīng)的理解首先,是單線程語言,也就意味著同一個(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是單線程語言,也就意味著同一個(gè)時(shí)間只能做一件事,那么 為什么JavaScript不是多線程呢?這樣還能提...
摘要:一個(gè)頁面在瀏覽器顯示出來至少需要個(gè)線程,分別是引擎,渲染,事件觸發(fā)。其中事件觸發(fā)是獨(dú)立于其他個(gè)執(zhí)行的,而和是相互排斥的,也就是說同一個(gè)時(shí)間二者只有一個(gè)在工作。 作為DOM本身十分重要的2個(gè)異步執(zhí)行函數(shù),初學(xué)者感覺這個(gè)很不好理解,我簡單寫一寫我的理解 setTimeout (func, millisec); setInterval(func, millisec); 這兩個(gè)方法在形式看起來...
摘要:所以其實(shí)和所謂的異步調(diào)用事實(shí)上是通過將代碼段插入到代碼的執(zhí)行隊(duì)列中實(shí)現(xiàn)的。當(dāng)執(zhí)行和的時(shí)候,會(huì)根據(jù)你設(shè)定的時(shí)間準(zhǔn)確地找到代碼的插入點(diǎn)。綜上所述,其實(shí)終歸是單線程產(chǎn)物。無論如何異步都不可能突破單線程這個(gè)障礙。 發(fā)表過一片博客《跟著我用JavaScript寫計(jì)時(shí)器》,比較基礎(chǔ).....有網(wǎng)友說應(yīng)該寫一下setTimeout的原理和機(jī)制,嗯,今天就來寫一下吧: 直奔主題:setTimeout和...
閱讀 3326·2023-04-26 00:58
閱讀 1277·2021-09-22 16:04
閱讀 3323·2021-09-02 15:11
閱讀 1568·2019-08-30 15:55
閱讀 2348·2019-08-30 15:55
閱讀 3277·2019-08-23 18:41
閱讀 3470·2019-08-23 18:18
閱讀 2760·2019-08-23 17:53