任務隊列,事件循環 宏任務 微任務

javascript執行機制是基于事件循環的并發式的,事件循環負責處理代碼,收集和處理事件以及執行隊列中的子任務


可視化描述

棧(stack)

js運行時形成一個執行棧,

function foo(b) {
  let a = 10;
  return a + b + 11;
}

function bar(x) {
  let y = 3;
  return foo(x * y);
}

console.log(bar(7)); // 返回 42

當調用 bar 時,第一個幀被創建并壓入棧中,幀中包含了 bar 的參數和局部變量。 當 bar 調用 foo 時,第二個幀被創建并被壓入棧中,放在第一個幀之上,幀中包含 foo 的參數和局部變量。當 foo 執行完畢然后返回時,第二個幀就被彈出棧(剩下 bar 函數的調用幀 )。當 bar 也執行完畢然后返回時,第一個幀也被彈出,棧就被清空了。

堆(heap)

對象被分配在堆中,堆是一個用來表示一大塊(通常是非結構化的)內存區域的計算機術語。

隊列(queue)

一個 JavaScript 運行時包含了一個待處理消息的消息隊列。每一個消息都關聯著一個用以處理這個消息的回調函數。

setTimeout(function(){console.log('時間一到,請執行改回調函數')},1000)

事件循環 期間的某個時刻,運行時會從最先進入隊列的消息開始處理隊列中的消息。被處理的消息會被移出隊列,并作為輸入參數來調用與之關聯的函數。正如前面所提到的,調用一個函數總是會為其創造一個新的棧幀。

事件循環(event loop)

queue.waitForMessage() 會同步地等待消息到達(如果當前沒有任何消息等待被處理)

while (queue.waitForMessage()) {
queue.processNextMessage();
}

特點

  1. 單線程

每一個消息完整地執行后,其它消息才會被執行
缺點:當一個消息需要太長時間才能處理完畢時,Web應用程序就無法處理與用戶的交互,例如點擊或滾動
2.永不阻塞
JavaScript的事件循環模型與許多其他語言不同的一個非常有趣的特性是,它永不阻塞。 處理 I/O 通常通過事件和回調來執行,所以當一個應用正等待一個 IndexedDB 查詢返回或者一個 XHR 請求返回時,它仍然可以處理其它事情,比如用戶輸入。

總結一下事件循環的機制:

(1) 所有任務在執行棧上執行,
(2) 綁定事件和異步事件(消息)放置于任務隊列
(3) 執行棧執行完畢,一直詢問任務隊列是否有消息需要執行,如果有就將關聯的回調函數放置于執行棧,準備執行

宏任務(macrotask)和微任務(mircrotask)

異步任務細分為宏任務和微任務,當一個宏任務執行完,會在渲染前,將執行期間所產生的所有微任務都執行完

宏任務 -> 微任務 -> GUI渲染 -> 宏任務 -> ...

宏任務:

  • 主代碼塊
  • setTimeout
  • setTimeInterval
  • setImmediate()-node
  • requestAnimationFrame -瀏覽器
  • postMessage
  • I/O
  • UI交互事件
    微任務:
  • process.nextTick ()-Node
  • Promise.then()
  • catch
  • finally
  • Object.observe
  • MutationObserver
圖解宏任務和微任務

注意點

  1. 瀏覽器會先執行一個宏任務,緊接著執行當前執行棧產生的微任務,再進行渲染,然后再執行下一個宏任務
  2. 微任務和宏任務不在一個任務隊列

總結

*執行主線程,遇到異步置入任務隊列,并在任務隊列根據宏任務和微任務進行區分
*執行棧完成,查看任務隊列,首先查看宏任務隊列有沒有要執行的任務,沒有就過,有就執行

  • 每個宏任務執行完都要查看微任務隊列,有沒有要執行的任務,沒有就過,有就執行,直到微任務隊列為空

測試:

function test() {
  console.log(1)
  setTimeout(function () {  // timer1
    console.log(2)
  }, 1000)
}

test();

setTimeout(function () {        // timer2
  console.log(3)
})

new Promise(function (resolve) {
  console.log(4)
  setTimeout(function () {  // timer3
    console.log(5)
  }, 100)
  resolve()
}).then(function () {
  setTimeout(function () {  // timer4
    console.log(6)
  }, 0)
  console.log(7)
})

console.log(8)

結合我們上述的JS運行機制再來看這道題就簡單明了的多了
JS是順序從上而下執行
執行到test(),test方法為同步,直接執行,console.log(1)打印1
test方法中setTimeout為異步宏任務,回調我們把它記做timer1放入宏任務隊列
接著執行,test方法下面有一個setTimeout為異步宏任務,回調我們把它記做timer2放入宏任務隊列
接著執行promise,new Promise是同步任務,直接執行,打印4
new Promise里面的setTimeout是異步宏任務,回調我們記做timer3放到宏任務隊列
Promise.then是微任務,放到微任務隊列
console.log(8)是同步任務,直接執行,打印8
主線程任務執行完畢,檢查微任務隊列中有Promise.then
開始執行微任務,發現有setTimeout是異步宏任務,記做timer4放到宏任務隊列
微任務隊列中的console.log(7)是同步任務,直接執行,打印7
微任務執行完畢,第一次循環結束
檢查宏任務隊列,里面有timer1、timer2、timer3、timer4,四個定時器宏任務,按照定時器延遲時間得到可以執行的順序,即Event Queue:timer2、timer4、timer3、timer1,依次拿出放入執行棧末尾執行 (插播一條:瀏覽器 event loop 的 Macrotask queue,就是宏任務隊列在每次循環中只會讀取一個任務)
執行timer2,console.log(3)為同步任務,直接執行,打印3
檢查沒有微任務,第二次Event Loop結束
執行timer4,console.log(6)為同步任務,直接執行,打印6
檢查沒有微任務,第三次Event Loop結束
執行timer3,console.log(5)同步任務,直接執行,打印5
檢查沒有微任務,第四次Event Loop結束
執行timer1,console.log(2)同步任務,直接執行,打印2
檢查沒有微任務,也沒有宏任務,第五次Event Loop結束
結果:1,4,8,7,3,6,5,2

console.log('start')
setTimeout(function(){
  console.log('宏任務1號')
})
Promise.resolve().then(function(){
    console.log('微任務0號')
  })
console.log('執行棧執行中')
setTimeout(function(){
  console.log('宏任務2號')
  Promise.resolve().then(function(){
    console.log('微任務1號')
  })
},500)

setTimeout(function(){
  console.log('宏任務3號')
 setTimeout(function(){
  console.log('宏任務4號')
  Promise.resolve().then(function(){
    console.log('微任務2號')
  })
},500)
 Promise.resolve().then(function(){
    console.log('微任務3號')
  })
},600)
console.log('end')

參考

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,428評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,024評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,285評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,548評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,328評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,878評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,971評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,098評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,616評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,554評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,725評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,243評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,971評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,361評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,613評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,339評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,695評論 2 370

推薦閱讀更多精彩內容