首先我們要知道瀏覽器是由什麼組成的
1.js主執行緒
1.1.heap(堆)
- 堆:由作業系統自動分配釋放 ,存放函式的引數值,區域性變數的值等。特點先進後出(陣列的shift方法)
let arr = [];
arr.push(1);
arr.push(2);
console.log(arr.shift()); // 1
複製程式碼
1.2.stack(棧)執行上下文
- 棧:會自動分配記憶體空間,會自動釋放,存放基本型別,簡單的資料段,佔據固定大小的空間 特點先進後出(函式執行的銷燬過程)
- 當前棧也叫執行上下文(執行同步任務)
同步任務:在主執行緒上排隊執行的任務,只有前一個任務執行完畢,才能執行後一個任務;
alert("不關閉後面是不會執行的");
console.log(1);
複製程式碼
2.WebAPIs (DOM,ajax,setTimeout)
3.callback queue(回撥/任務 佇列)
3.1任務佇列的特點:先進先出,先放進去的非同步任務先執行
setTimeout(()=>{
console.log(1);
},300)
setTimeout(()=>{
console.log(3);
},200)
setTimeout(()=>{
console.log(2);
},200)
- 輸出的結果是 3 2 1
複製程式碼
3.2任務佇列裡面存放的是非同步任務(巨集任務,微任務)
非同步任務:不進入主執行緒、而進入"任務佇列"的任務,只有"任務佇列"通知主執行緒,某個非同步任務可以執行了,該任務才會進入主執行緒執行。
for(var i = 0; i < 5; i++){
setTimeout(() =>console.log(i), 0);
}
console.log("ok");
// 先輸出ok,再輸出5個5
複製程式碼
3.1.1非同步任務的分類
- 1.macro-task(巨集任務): setTimeout, setInterval, setImmediate(ie), I/O MessageChannel
- 2.micro-task(微任務): process.nextTick, 原生Promise,Object.observe(已廢棄),MutationObserver(h5的一個方法,在dom更新完之後執行)
3.1.2非同步任務的執行順序
微任務的執行順序在巨集任務之前
setTimeout(()=>{
console.log("setTimeout1");
},0)
Promise.resolve().then(()=>{
console.log("Promise");
})
process.nextTick(()=>{
console.log("nextTick");
})
// 輸出 nextTick Promise setTimeout1
複製程式碼
通過上面的瞭解我們大致知道瀏覽器是先執行同步任務,執行完之後再執行非同步任務。
回到主題,我們來看看瀏覽器是怎麼實現一個事件環(for)的
-
1.所有同步任務都在主執行緒上執行,形成一個執行棧
-
2.主執行緒之外,還存在一個任務佇列。只要非同步任務有了執行結果,就在任務佇列之中放置一個事件
-
3.一旦執行棧中的所有同步任務執行完畢,系統就會讀取任務佇列,將佇列中的事件放到執行棧中依次執行
-
4.主執行緒從任務佇列中讀取事件,這個過程是迴圈不斷的
整個的這種執行機制又稱為Event Loop(事件迴圈) 複製程式碼
看下面一段程式碼
setTimeout(function(){
console.log('setTimeout1');
Promise.resolve().then(()=>{
console.log('then1');
});
},0)
Promise.resolve().then(()=>{
console.log('then2');
Promise.resolve().then(()=>{
console.log('then3');
});
setTimeout(function(){
console.log('setTimeout2');
},0)
})
// 輸出結果 then2 then3 setTimeout1 then1 setTimeout2
複製程式碼
我們得出一個結果
瀏覽器的事件環和任務佇列裡面微任務和巨集任務的關係
- 先執行棧中的內容 執行後 清空微任務
- 取一個巨集任務 再去清空微任務 ,再去取巨集任務,一直到任務佇列中沒有為止
最後再說一下,node的事件環和任務佇列裡面微任務和巨集任務的關係
- 本質上和瀏覽器的事件環不變就是佇列中微任務和巨集任務的執行順序有些差別
- 先執行棧中的內容 執行後 清空微任務
- 清空巨集任務 再去清空微任務 ,再去清空巨集任務,一直到任務佇列中沒有為止