咱們都知道JavaScript是單線程的,也就是說同一時間只能幹一件事。這是由於JavaScript主要是用來操做DOM
的,若是變成多線程,瀏覽器就懵逼了,不知道該聽誰的了。可是雖然js是單線程,可是徹底能夠模擬多線程,靠的就是Event Loop
。node
咱們都知道js中的代碼分 同步
和 異步
,所謂的 異步
其實就是不會阻塞咱們的主線程,等待主線程的代碼執行完畢纔會執行。callback setTimeout setInterval Promise ...
這些都是都是咱們耳熟能詳的 異步
代碼ajax
如圖所示,js中的內存分爲 堆內存(heap)
和 棧內存(stack)
, 堆內存
中存的是咱們聲明的object
類型的數據,棧內存
中存的是 基本數據類型
以及 函數執行時
的運行空間。咱們的 同步
代碼就放在 執行棧
中,那異步代碼呢?瀏覽器會將 dom事件 ajax setTimeout
等異步代碼放到隊列中,等待執行棧
中的代碼都執行完畢,纔會執行隊列中的代碼,是否是有點像發佈訂閱模式。promise
console.log(1);
setTimeout(() => {
console.log(2);
}, 0);
console.log(3);
複製代碼
根據以前說的,setTimeout 會被放到隊列中,等待執行棧中的代碼執行完畢纔會執行,因此會輸出1, 3, 2
瀏覽器
可是異步
代碼也是有區別的:bash
console.log(1)
setTimeout(() => {
console.log(2)
}, 0)
Promise.resolve().then(() => {
console.log(3)
})
複製代碼
輸出的永遠是1, 3, 2
, 也就是說 promise
在 setTimeout
以前執行了。這是由於 異步任務
分爲 微任務(microtask)
和 宏任務(task)
,執行的順序是 執行棧中的代碼 => 微任務 => 宏任務
。多線程
執行棧
中的代碼永遠最早執行promise MutationObserver...
執行棧
中的代碼執行完畢,會在執行宏任務隊列
以前先看看微任務隊列
中有沒有任務,若是有會先將微任務隊列
中的任務清空纔會去執行宏任務隊列
setTimeout setInterval setImmediate(IE專用) messageChannel...
執行棧
和微任務隊列
都執行完畢纔會執行,而且在執行完每個宏任務
以後,會去看看微任務隊列
有沒有新添加的任務,若是有,會先將微任務
隊列中的任務清空,纔會繼續執行下一個宏任務
setTimeout(() => {
console.log('timeout1')
Promise.resolve().then(() => {
console.log('promise1')
})
Promise.resolve().then(() => {
console.log('promise2')
})
}, 100)
setTimeout(() => {
console.log('timeout2')
Promise.resolve().then(() => {
console.log('promise3')
})
}, 200)
複製代碼
setTimeout
塞到宏任務隊列中setTimeout1
時間到了執行的時候,首先打印timeout1,而後在微任務隊列中塞入promise1
和promise2
setTimeout1
執行完畢後,會去微任務隊列檢查是否是空的,他發現了有兩個promise
,會把兩個promise
按順序執行完再去執行下一個宏任務promise
執行完畢後會微任務隊列中沒有任務了,會去宏任務中執行下一個任務 setTimeout2
setTimeout2
執行的時候,先打印一個timeout2,而後又在微任務隊列中塞了一個promise2
setTimeout2
執行完畢後會去微任務隊列檢查,發現有一個promise3,會將promise3
執行timeout1 promise1 promise2 timeout2 promise3
咱們都知道Node.js 是一個基於 Chrome V8 引擎的 JavaScript 運行環境,也就是可以讓js在服務端運行。可是Node中的Event Loop是用libuv模擬的,它將不一樣的任務分配給不一樣的線程,造成一個Event Loop,以異步的方式將任務的執行結果返回給V8引擎。dom
process.nextTric promise setImmediate...
setTimeout setInterval...
Node中的Event Loop會在每次切換隊列的時候 清空微任務隊列,也就會會將當前隊列都執行完,在進入下一階段的時候檢查一下微任務中有沒有任務異步
setTimeout(() => {
console.log('timeout1')
Promise.resolve().then(() => {
console.log('promise1')
})
Promise.resolve().then(() => {
console.log('promise2')
})
}, 0)
setTimeout(() => {
console.log('timeout2')
Promise.resolve().then(() => {
console.log('promise3')
})
}, 0)
複製代碼
setTimeout
塞到宏任務隊列中setTimeout1
時間到了執行的時候,首先打印timeout1,而後在微任務隊列中塞入promise1
和promise2
setTimeout1
執行完畢後,繼續執行下一個setTimeout2
setTimeout2
執行的時候,先打印一個timeout2,而後又在微任務隊列中塞了一個promise2
timeout1 timeout2 promise1 promise2 promise3