js事件循環

console.log('begin');
setTimeout(function() { console.log('timeout') });
new Promise(function(resolve) {
    for (let i = 0; i < 3; i++) {
        if (i == 1) resolve();
        console.log(i);
    }
    console.log('promise')
}).then(function() {
    console.log('then')
})
console.log('end');

上述代碼依次輸出:begin、0、一、二、promise、end、then、timeoutajax

js的一個特色就是單線程,可是不少時候咱們仍然須要在不一樣的時間去執行不一樣的任務,例如給元素添加點擊事件,設置一個定時器,或者發起ajax請求,所以須要一個異步機制來達到這樣的目的,事件循環機制也所以而來。promise

每個js程序都擁有惟一的事件循環,大多數代碼的執行順序是能夠根據函數調用棧的規則執行的,而setTimeout/setInterval或者不一樣的事件綁定(click、mousedown等)中的代碼,則經過隊列來執行。瀏覽器

任務隊列又分爲宏任務(macro-task)與微任務(micro-task)兩種,在瀏覽器中,包括:異步

  • macro-task:script(總體代碼)、setTimeout/setInterval、I/O、UI rendering等
  • micro-task:Promise、MutationObserver

事件循環的順序,決定了js代碼的執行順序:
首先從macro-task中的script開始第一次循環。此時全局上下文進入函數調用棧,直到調用棧清空,在這個過程當中,若是遇到任務分發器(例如timer、promise),就會將任務放入對應隊列中去函數

第一次循環時,macro-task中其實只有script,所以函數調用棧清空以後,會直接執行全部的micro-task。當全部可執行的micro-task執行完畢以後,就表示第一次事件循環結束線程

第二次循環會再次從macro-task開始執行。此時macro-task中的script隊列已經沒有任務了,可是可能會有其餘的隊列任務,而micro-task中暫時尚未任務。此時會先選擇其中一個宏任務隊列,例如setTimeout,將該隊列中全部的任務所有執行完畢,而後再執行此過程當中可能產生的微任務。微任務執行完畢以後,再回過頭來執行其餘宏任務隊列中的任務。以此類推,直到全部宏任務隊列中的任務都被執行了,而且清空了微任務,第二次循環就會結束code

若是在第二次循環過程當中,產生了新的宏任務隊列,或者以前宏任務隊列中的任務暫時沒有知足執行條件,例如延遲時間不夠或者事件沒有被觸發,那麼將會繼續以一樣的順序重複循環server

相關文章
相關標籤/搜索