對於JavaScript咱們都知道,他是個單線程語言,可是準確來講它是擁有一個執行程序主線程,和消息隊列輔線程(Event Loop),以及各個真正處理異步操做的工做線程。
當主線程執行JS程序的時候,若是遇到了異步的操做(如:click事件,setTimeOut,I/0操做,異步請求,Promise等),主線程將各個異步任務交給工做線程,主線程繼續執行,工做線程會判斷是否到了要執行該異步操做的條件了,若是工做線程判斷已經到了要執行工做線程的條件以後,就會把回調函數放入輔線程Event Loop的macrotask任務隊列或者microtask任務隊列的隊尾。當上述主線程執行完後續同步調用的代碼以後,輔線程會一直循環上面兩個隊列,首先執行的是microtask任務隊列,並且該任務隊列是該次循環就會執行完並清空的,macrotask會等到下次event loop循環的時候執行。web
Examplepromise
1. console.log(1); 2. setTimeout(function timerCallback(){ 3. console.log(2); 4. },0) 5. new Promise(function execute(resolve,reject){ 6. console.log(3); 7. if(true) 8. resolve(); 9. }).then(function resolveCallback(){ 10. console.log(4); 11. }); 12. console.log(5); // 上面程序執行的順序是:1,3,5,4,2
代碼詳解:當主線程執行上述代碼的時候,從上往下執行:
一、先將console.log(1)這句代碼作一個入棧執行的操做,打印出1,該句代碼沒有後續的方法調用了,就出棧銷燬;異步
二、執行setTimeout,將改句代碼入棧執行,判斷到該方法屬於WebAPIs(JS工做線程提供API的統稱,其中包含了webcore工做模塊提供了DOM Binding、network、timer等),timerCallback方法出棧,交給工做線程webcore下的timer模塊,這裏timer模塊會判斷是否到了執行條件了,因爲是延時是0,因此timer模塊判斷能夠執行了,並將回調函數timerCallback放到輔助線程Event Loop的macrotask隊尾,等待下一次Event Loop循環去執行。函數
三、繼續執行Promise這句代碼(包括then語句),將其入棧執行,判斷該Promise屬於Promise模塊(非WebAPIs),將其then的回調函數交給Promise模塊,有後續調用;將execute方法入棧執行,有後續調用;將console.log(3)入棧執行,打印出3,console.log(3)執行完畢,出棧銷燬;有後續調用if(true)入棧執行,判斷爲true,出棧銷燬,繼續將resolve()入棧執行,判斷resolve()是WebAPIs的成功的回調,執行的時候通知到上面的Promise模塊,Promise模塊將成功的回調放到Event Loop的microtask隊尾,resolve()出棧銷燬,無後續調用,Promise出棧銷燬。oop
四、繼續執行,將console.log(5)入棧執行,打印出5,無後續調用,出棧銷燬。線程
五、Event Loop開始循環microtask隊列,將resolveCallback()入棧執行,有後續調用;將console.log(4)入棧執行,打印出4,出棧銷燬;無後續調用,resolveCallback()出棧銷燬,清空隊列。code
六、Event Loop開始循環macrotask隊列,將timerCallback()入棧執行,有後續調用;將console.log(2)入棧執行,打印出2,出棧銷燬,無後續調用;將timerCallback()出棧銷燬,清空隊列。server
macrotask任務隊列的來源有:隊列
setTimeout事件
setInterval
setImmediate
I/O
UI rendering
microtask任務隊列的來源有:
process.nextTick
promises
Object.observe
MutationObserver