做者:葉@毛豆前端javascript
js的事件循環機制,在我理解起來就是執行上下文,對函數的出棧和入棧的一個過程。都知道js的一大特色是單線程,這也是這個語言的核心特徵。試想一下,若是js是個多線程的語言,同時存在兩個線程,一個線程是在某個Dom上添加節點,而另外一個線程倒是刪除節點,這個時候瀏覽器就會產生錯亂,而咱們關心的js事件循環機制,正是由js的單線程特質決定的。前端
先上圖,看下大體流程java
在上圖的過程當中:涉及的到異步進程:git
知道了js的大體執行的過程了,咱們看下其中涉及到的一些概念github
知道了棧是一種後進先出的數據結構後,咱們運行一下代碼,並模擬它的入棧和出棧過程棧(stack)又名堆棧,它是一種運算受限的線性表。其限制是僅容許在表的一端進行插入和刪除運算ajax
function fun2() {
console.log('fun2')
}
function fun1() {
fun2();
}
setTimeout(() => {
console.log('setTimeout')
})
fun1();
複製代碼
以上的出入棧如圖所示瀏覽器
js中存在着多個任務隊列,而且不一樣的任務隊列之間優先級不一樣,優先級高的先被獲取。同一隊列中按照隊列順序被取用 任務隊列分爲兩種類型數據結構
二者的區別:多線程
事實上,事件循環的順序,決定了JavaScript代碼的執行順序。執行時從script(總體代碼)開始第一次循環,以後全局上下文進入函數調用棧,直到執行棧清空,而後開始執行全部的microtask,當全部可執行的micro-task執行完畢以後。循環再次從macro-task開始,找到其中一個任務隊列執行完畢,而後再執行全部的micro-task,這樣一直循環下去。事件循環每次只會入棧一個 macrotask ,主線程執行完該任務後又會先檢查 microtasks 隊列並完成裏面的全部任務後再執行 macrotask。異步
咱們舉個例子驗證下吧:
console.log('-----start-----')
setTimeout(()=>{
console.log('setTimeout1-macroTask')
},1000)
Promise.resolve().then(() => {
console.log('Promise1-microTask')
});
Promise.resolve().then(() => {
console.log('Promise2-microTask')
});
setTimeout(()=>{
console.log('setTimeout2-macroTask')
},100)
console.log('-----end-----')
輸出結果
-----start-----
-----end-----
Promise1-microTask
Promise2-microTask
setTimeout2-microTask
setTimeout1-microTask
複製代碼
具體過程,咱們稍微歸納下: