在理解事件循環以前,我總會遇到一些奇奇怪怪的問題:好比明明已經調接口拿到了數據,但是跟在調數據以後的操做卻沒有正常執行;又或者不知道爲啥,代碼裏非得加個setTimeout
才能正常跑通;特別是在運用Promise的時候,更是有各類問題百思不得解。趕上問題要解決,更要知道問題產生的緣由,這樣才能hold住全場!前端
廢話很少說了,先來看一段代碼ajax
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');
結果是start resolve end then setTimeout1 setTimeout3 settimeout2
。數據結構
在分析結果以前,我先來科普幾個概念,這些概念的表述不必定與標準徹底對應,可是能夠幫助你更容易理解JS的事件機制異步
咱們知道,js是單線程的,這就是說,只有一個主線程,主線程會自上而下依次執行調用棧中的事件。任務隊列中的代碼被加載到函數調用棧中去執行。當前的宏任務隊列中的代碼執行完畢後,會執行本次宏任務隊列中分發到微任務隊列中的代碼。而後執行下一個宏任務隊列中的代碼,依次循環。函數
這裏要提一點容易誤解的地方,setTimeout
函數自己,實際上是當即執行的,它內部的任務,纔會被分發到任務隊列中延時執行。spa
setTimeout
的時候,新建了一個宏任務隊列,函數內的任務被分發這個隊列中等待執行Promise
,注意,Promise
中的第一個function中的代碼會立馬開始執行,遇到resolve
或者reject
後,then
方法中函數會被分發到本次事件循環的微任務隊列中等待執行。因此這裏立馬打印出了'resolve'。遇到setTimeout2
後,一樣新建了一個宏任務隊列,其中的函數被分發到了這個新的宏任務隊列中,then
方法中的操做被分發到了微任務隊列中等待console
操做,因此並無再分發新的任務隊列,可是因爲第二個setTimeout
設定了200毫秒的延時,因此‘setTimeout2’被最後打印。說到這裏,你基本上對事件循環有個大體的瞭解了。以前有個同窗問過我一個問題,點擊輪播圖下一頁,可是頁面沒有反應,代碼是這樣的:線程
這個函數是點擊下一頁的按鈕後輪播圖轉動,他在getNextPhoto
函數中調接口獲取了下個頁面的數據,goToPage
函數裏是讓輪播圖切換的操做。相信若是你讀懂了這篇文章,就會知道問題出在了哪裏。顯然獲取數據ajax
是個異步操做,他被分發到了事件隊列中等待執行,因此還沒等數據回來,翻頁的操做已經開始執行,因爲沒有數據,並無按預期效果顯示。解決方法就是在getNextPhoto
函數裏調接口拿到數據以後,再通知去執行goToPage
操做,問題就解決了。code
做爲一個前端菜鳥,但願獲得各位大神的批評指正!server