摘要:任務(wù)隊(duì)列中的代碼被加載到函數(shù)調(diào)用棧中去執(zhí)行。說(shuō)到這里,你基本上對(duì)事件循環(huán)有個(gè)大致的了解了。
在理解事件循環(huán)之前,我總會(huì)遇到一些奇奇怪怪的問(wèn)題:比如明明已經(jīng)調(diào)接口拿到了數(shù)據(jù),可是跟在調(diào)數(shù)據(jù)之后的操作卻沒(méi)有正常執(zhí)行;又或者不知道為啥,代碼里非得加個(gè)setTimeout才能正常跑通;特別是在運(yùn)用Promise的時(shí)候,更是有各種問(wèn)題百思不得解。遇上問(wèn)題要解決,更要知道問(wèn)題產(chǎn)生的原因,這樣才能hold住全場(chǎng)!
廢話不多說(shuō)了,先來(lái)看一段代碼
console.log("start"); setTimeout(function(){ console.log("setTImeout1") },0); new Promise(function(resolve,reject){ console.log("resolve") setTimeout(function(){ console.log("setTimeout2") },200); resolve() }).then(function(){ console.log("then") }); setTimeout(function(){ console.log("setTimeout3") },0); console.log("end");
結(jié)果是start resolve end then setTimeout1 setTimeout3 settimeout2。
在分析結(jié)果之前,我先來(lái)科普幾個(gè)概念,這些概念的表述不一定與標(biāo)準(zhǔn)完全對(duì)應(yīng),但是可以幫助你更容易理解JS的事件機(jī)制
宏任務(wù)(macro-task):包括js整體代碼,setTimeout,setInterval,setImmediate ,I/O, UI renderder等
微任務(wù)(micro-task):包括Promise,Object.observe,process.nextTick,MutationObserver等
調(diào)用棧:js被加載進(jìn)來(lái)之后,會(huì)從上至下讀取代碼,同步代碼被立即執(zhí)行,而異步代碼被加入事件隊(duì)列中
事件隊(duì)列:一些沒(méi)有被立即執(zhí)行的代碼被添加到事件隊(duì)列中,隊(duì)列是一種先進(jìn)先出的數(shù)據(jù)結(jié)構(gòu),也就是說(shuō),先加入事件隊(duì)列的任務(wù)會(huì)被優(yōu)先執(zhí)行
我們知道,js是單線程的,這就是說(shuō),只有一個(gè)主線程,主線程會(huì)自上而下依次執(zhí)行調(diào)用棧中的事件。任務(wù)隊(duì)列中的代碼被加載到函數(shù)調(diào)用棧中去執(zhí)行。當(dāng)前的宏任務(wù)隊(duì)列中的代碼執(zhí)行完畢后,會(huì)執(zhí)行本次宏任務(wù)隊(duì)列中分發(fā)到微任務(wù)隊(duì)列中的代碼。然后執(zhí)行下一個(gè)宏任務(wù)隊(duì)列中的代碼,依次循環(huán)。
這里要提一點(diǎn)容易誤解的地方,setTimeout函數(shù)本身,其實(shí)是立即執(zhí)行的,它內(nèi)部的任務(wù),才會(huì)被分發(fā)到任務(wù)隊(duì)列中延時(shí)執(zhí)行。
代碼被加載后,全局上下文進(jìn)入函數(shù)調(diào)用棧,緊接著,‘start’被執(zhí)行
遇到setTimeout的時(shí)候,新建了一個(gè)宏任務(wù)隊(duì)列,函數(shù)內(nèi)的任務(wù)被分發(fā)這個(gè)隊(duì)列中等待執(zhí)行
此時(shí)遇到了Promise,注意,Promise中的第一個(gè)function中的代碼會(huì)立馬開始執(zhí)行,遇到resolve或者reject后,then方法中函數(shù)會(huì)被分發(fā)到本次事件循環(huán)的微任務(wù)隊(duì)列中等待執(zhí)行。所以這里立馬打印出了"resolve"。遇到setTimeout2后,同樣新建了一個(gè)宏任務(wù)隊(duì)列,其中的函數(shù)被分發(fā)到了這個(gè)新的宏任務(wù)隊(duì)列中,then方法中的操作被分發(fā)到了微任務(wù)隊(duì)列中等待
代碼繼續(xù)往下,遇到"setTimeout3"后再次新建了一個(gè)新的宏任務(wù)隊(duì)列
"end"被立即執(zhí)行。此時(shí)有三個(gè)宏任務(wù)隊(duì)列,一個(gè)微任務(wù)隊(duì)列
微任務(wù)隊(duì)列中的操作被執(zhí)行,也就是打印出了‘then’,此時(shí),第一輪的事件循環(huán)結(jié)束。
第一輪的事件循環(huán)結(jié)束,開始下一輪的事件循環(huán),依次執(zhí)行每個(gè)宏任務(wù)隊(duì)列中的內(nèi)容,我們這里宏任務(wù)隊(duì)列中的函數(shù)比較簡(jiǎn)單,都是console操作,所以并沒(méi)有再分發(fā)新的任務(wù)隊(duì)列,但是由于第二個(gè)setTimeout設(shè)定了200毫秒的延時(shí),所以‘setTimeout2’被最后打印。
說(shuō)到這里,你基本上對(duì)事件循環(huán)有個(gè)大致的了解了。之前有個(gè)同學(xué)問(wèn)過(guò)我一個(gè)問(wèn)題,點(diǎn)擊輪播圖下一頁(yè),但是頁(yè)面沒(méi)有反應(yīng),代碼是這樣的:
這個(gè)函數(shù)是點(diǎn)擊下一頁(yè)的按鈕后輪播圖轉(zhuǎn)動(dòng),他在getNextPhoto函數(shù)中調(diào)接口獲取了下個(gè)頁(yè)面的數(shù)據(jù),goToPage函數(shù)里是讓輪播圖切換的操作。相信如果你讀懂了這篇文章,就會(huì)知道問(wèn)題出在了哪里。顯然獲取數(shù)據(jù)ajax是個(gè)異步操作,他被分發(fā)到了事件隊(duì)列中等待執(zhí)行,所以還沒(méi)等數(shù)據(jù)回來(lái),翻頁(yè)的操作已經(jīng)開始執(zhí)行,由于沒(méi)有數(shù)據(jù),并沒(méi)有按預(yù)期效果顯示。解決方法就是在getNextPhoto函數(shù)里調(diào)接口拿到數(shù)據(jù)之后,再通知去執(zhí)行goToPage操作,問(wèn)題就解決了。
作為一個(gè)前端菜鳥,希望得到各位大神的批評(píng)指正!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/107961.html
摘要:但是事件循環(huán)一般會(huì)在主線程中任務(wù)執(zhí)行完成之后執(zhí)行。所以,上面函數(shù)的調(diào)用棧過(guò)程如下總結(jié)的事件循環(huán)部分,內(nèi)容應(yīng)該算是全部闡述完全了。 前言 還記得那些年面試官問(wèn)你的定時(shí)器的原理嗎?還有呢?Promise的原理呢?原理、原理、原理,問(wèn)的我們懷疑人生。 為了下次不再懵逼,今天,我們來(lái)了解一下Event Loop的概念。我們的初衷是真正的了解和掌握它,了解整體JavaScript的運(yùn)行機(jī)制。至少...
摘要:事件完成,回調(diào)函數(shù)進(jìn)入。我們來(lái)分析一段較復(fù)雜的代碼,看看你是否真的掌握了的執(zhí)行機(jī)制第一輪事件循環(huán)流程分析如下整體作為第一個(gè)宏任務(wù)進(jìn)入主線程,遇到,輸出。宏任務(wù)微任務(wù)第三輪事件循環(huán)宏任務(wù)執(zhí)行結(jié)束,執(zhí)行兩個(gè)微任務(wù)和。 關(guān)于JavaScript 首先js是單線程的,執(zhí)行任務(wù)肯定是一個(gè)接著一個(gè)。在最新的html5中提出了web-worker,但是JavaScript是單線程這一核心沒(méi)有改變,一...
摘要:關(guān)于這部分有嚴(yán)格的文字定義,但本文的目的是用最小的學(xué)習(xí)成本徹底弄懂執(zhí)行機(jī)制,所以同步和異步任務(wù)分別進(jìn)入不同的執(zhí)行場(chǎng)所,同步的進(jìn)入主線程,異步的進(jìn)入并注冊(cè)函數(shù)。宏任務(wù)微任務(wù)第三輪事件循環(huán)宏任務(wù)執(zhí)行結(jié)束,執(zhí)行兩個(gè)微任務(wù)和。 不論你是javascript新手還是老鳥,不論是面試求職,還是日常開發(fā)工作,我們經(jīng)常會(huì)遇到這樣的情況:給定的幾行代碼,我們需要知道其輸出內(nèi)容和順序。 因?yàn)閖avascr...
摘要:事件完成,回調(diào)函數(shù)進(jìn)入。主線程從讀取回調(diào)函數(shù)并執(zhí)行。終于執(zhí)行完了,終于從進(jìn)入了主線程執(zhí)行。遇到,立即執(zhí)行。宏任務(wù)微任務(wù)第三輪事件循環(huán)宏任務(wù)執(zhí)行結(jié)束,執(zhí)行兩個(gè)微任務(wù)和。事件循環(huán)事件循環(huán)是實(shí)現(xiàn)異步的一種方法,也是的執(zhí)行機(jī)制。 本文的目的就是要保證你徹底弄懂javascript的執(zhí)行機(jī)制,如果讀完本文還不懂,可以揍我。不論你是javascript新手還是老鳥,不論是面試求職,還是日常開發(fā)工作...
js運(yùn)行機(jī)制-事件循環(huán)EventLoop 先來(lái)看看一段js代碼: console.log(script begin) setTimeout(() => { console.log(setTimeout) },0) new Promise((resolve) => { console.log(promise begin) for(let i = 0; i < 1000; i...
閱讀 1176·2021-10-11 10:59
閱讀 1963·2021-09-29 09:44
閱讀 853·2021-09-01 10:32
閱讀 1424·2019-08-30 14:21
閱讀 1870·2019-08-29 15:39
閱讀 2973·2019-08-29 13:45
閱讀 3531·2019-08-29 13:27
閱讀 2006·2019-08-29 12:27