我們都知道javascript是單執行緒語言,就是因為單執行緒的特性,就不得不提js中的同步和異步
一、同步和異步
所謂單執行緒,無非就是同步佇列和異步佇列,js代碼是自上向下執行的,在主執行緒中立即執行的就是同步任務,比如簡單的邏輯操作及函式,而異步任務不會立馬立馬執行,會挪步放到到異步佇列中,比如ajax、promise、事件、計時器等等,
也就是先執行同步,主執行緒結束后再按照異步的順序再次執行,
二、時間回圈(Event Loop)
Event Loop是什么?中文翻譯是事件回圈,等待主執行緒中任務全部完成后,再回來把異步佇列中任務放到主程式中運行,這樣反復的回圈,就是事件回圈,

先來看組代碼
console.log('開始111');
setTimeout(function() {
console.log('setTimeout111');
}, 0);
Promise.resolve().then(function() {
console.log('promise111');
}).then(function() {
console.log('promise222');
});
console.log('開始222');
我們猜想一下上面的代碼,會怎樣列印?我們知道,肯定是先走同步的代碼,從上往下,先列印 “開始111”,再列印“開始222”,
中途的三個異步,進入到了異步佇列,等待同步執行完(列印完),回傳來再執行異步,所以是后列印出來,
列印的結果先放一放,我們稍后回來再說,現在我們中途插播一段知識點:
三、宏觀任務和微觀任務(先執行微觀任務,再執行宏觀任務):
在事件回圈中,每進行一次回圈操作稱為tick,tick 的任務處理模型是比較復雜的,里邊有兩個詞:分別是 Macro Task (宏任務)和 Micro Task(微任務),
簡單來說:
宏觀任務主要包含:setTimeout、setInterval、script(整體代碼)、I/O、UI 互動事件、setImmediate(Node.js 環境)
微觀任務主要包括:Promise、MutaionObserver、process.nextTick(Node.js 環境)
規范:先執行微觀任務,再執行宏觀任務
那么我們知道了,Promise 屬于微觀任務, setTimeout、setInterval 屬于宏觀任務,先執行微觀任務,等微觀任務執行完,再執行宏觀任務,所以我們再看一下這個代碼:
console.log('開始111');
setTimeout(function() {
console.log('setTimeout111');
}, 0);
Promise.resolve().then(function() {
console.log('promise111');
}).then(function() {
console.log('promise222');
});
console.log('開始222');
我們按照步驟來分析下:
1、遇到同步任務,直接先列印 “開始111”,
2、遇到異步 setTimeout ,先放到佇列中等待執行,
3、遇到了 Promise ,放到等待佇列中,
4、遇到同步任務,直接列印 “開始222”,
5、同步執行完,回傳執行佇列中的代碼,從上往下執行,發現有宏觀任務 setTimeout 和微觀任務 Promise ,那么先執行微觀任務,再執行宏觀任務,
所以列印的順序為: 開始111 、開始222 、 promise111 、 promise222 、 setTimeout111 ,
同理,我們再來分析一個代碼:
console.log('開始111');
setTimeout(function () {
console.log('timeout111');
});
new Promise(resolve => {
console.log('promise111');
resolve();
setTimeout(() => console.log('timeout222'));
}).then(function () {
console.log('promise222')
})
console.log('開始222');
分析一下:
1、遇到同步代碼,先列印 “開始111” ,
2、遇到setTimeout異步,放入佇列,等待執行 ,
3、中途遇到Promise函式,函式直接執行,列印 “promise111”,
4、遇到setTimeout ,屬于異步,放入佇列,等待執行,
5、遇到Promise的then等待成功回傳,異步,放入佇列,
6、遇到同步,列印 “開始222”,
7、執行完,回傳,將異步佇列中的代碼,按順序執行,有一個微觀任務,then后的,所以列印 “promise222”,再執行兩個宏觀任務 “timeout111” “timeout222”,
所以,列印的順序為:開始111 、 promise111 、 開始222 、 promise222 、 timeout111 、 timeout222 .
先執行主任務,把異步任務放入回圈佇列當中,等待主任務執行完,再執行佇列中的異步任務,異步任務先執行微觀任務,再執行宏觀任務,一直這樣回圈,反復執行,就是事件回圈機制,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/11203.html
標籤:JavaScript
上一篇:js 作用域和作用域鏈
