一篇文章帶你瞭解vue.js的事件循環機制
一、事件循環機制介紹
JS是單線程的語言,瀏覽器和Node.js定義瞭各自的Event Loop(事件循環機制)則是用來解決異步問題。將程序分為“主線程(執行棧)”與“Event Loop線程”,“主線程”自上而下依次執行同步任務,“Event Loop線程”將異步任務推入宏任務隊列與微任務隊列去執行。
事件循環機制從整體上告訴瞭我們 JavaScript 代碼的執行順序 Event Loop 即事件循環,是指瀏覽器或Node 的一種解決javaScript 單線程運行時不會阻塞的一種機制,也就是我們經常使用異步的原理。“Event Loop線程”先執行宏任務隊列,然後執行微任務隊列,若微任務在執行過程中產生瞭新的微任務,則繼續執行微任務,微任務執行完畢後,再回到宏任務中進行下一輪循環。即繼續先執行宏任務隊列,再執行 微任務隊列。
宏任務:
script(整體代碼)/setTimeout/setInterval/setImmediate/ I/O / UI Rendering
微任務:
process.nextTick()/Promise/Async、Await(實際就是Promise)/MutationObserver(html5新特性)
setTimeout 和 setInterval 等都是任務源,真正進入任務隊列的是他們分發的任務。
優先級
setTimeout = setInterval 一個隊列setTimeout > setImmediate process.nextTick > Promise
二、經典事件循環面試題
1.在下面這段代碼是面試中關於這類問題的經典考題,其中包含瞭同步、異步任務,幾個輸出的先後順序是怎樣的。
setTimeout(function(){ console.log('1') }); new Promise(function(resolve){ console.log('2'); resolve(); }).then(function(){ console.log('3') }); console.log('4'); // 2,4,3,1
首先進行任務劃分,同步任務:new Promise()
、console.log('4')
;宏任務: setTimeout()
;微任務:Promise().then()
;Event Loop
依次將同步任務推入執行棧並執行,當遇到宏任務或微任務時,推到宏任務或微任務隊列中。先執行同步任務,同步隊列執行完畢,會去微隊列取任務,直到微隊列清空,再去宏隊列取任務執行。故此段程序執行順序為:
new Promise()
、console.log('4')
、Promise().then()
、setTimeout()
。
2.示例2
答案輸出為:async2 end => Promise => async1 end => promise1 => promise2 => setTimeout
3.示例3
mounted(){ this.test(); }, methods:{ test(){ console.log('script start'); this.async1(); setTimeout(function() { console.log('setTimeout') }, 0); new Promise(resolve => { console.log('Promise') resolve() }) .then(function() { console.log('promise1') }) .then(function() { console.log('promise2') }) console.log('script end') }, async async1() { await this.async2() console.log('async1 end') }, async async2() { console.log('async2 end') }, }
新版的chrome瀏覽器中不是如上打印的,因為chrome優化瞭,await變得更快瞭,輸出為:
// script start => async2 end => Promise => script end => async1 end => promise1 => promise2
分析這段代碼:
- 執行代碼,輸出script start。
- 執行async1(),會調用async2(),然後輸出async2 end,此時將會保留async1函數的上下文,然後跳出async1函數。
- 遇到setTimeout,產生一個宏任務
- 執行Promise,輸出Promise。遇到then,產生第一個微任務
- 繼續執行代碼,輸出script end
- 代碼邏輯執行完畢(當前宏任務執行完畢),開始執行當前宏任務產生的微任務隊列,輸出promise1,該微任務遇到then,產生一個新的微任務
- 執行產生的微任務,輸出promise2,當前微任務隊列執行完畢。執行權回到async1
- 執行await,實際上會產生一個promise返回,即
- let promise_ = new Promise((resolve,reject){ resolve(undefined)})
- 執行完成,執行await後面的語句,輸出async1 end 最後,執行下一個宏任務,即執行setTimeout,輸出setTimeout
- 註意以上分析是舊版瀏覽器await執行慢導致async1在微任務執行後執行。
總結
本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!
推薦閱讀:
- node事件循環中事件執行的順序
- 全面瞭解Node事件循環
- 關於js的事件循環機制剖析
- 深入瞭解Javascript的事件循環機制
- JS promise 的回調和 setTimeout 的回調到底誰先執行