咱們都知道javascript是單線程語言,就是由於單線程的特性,就不得不提js中的同步和異步javascript
1、同步和異步java
所謂單線程,無非就是同步隊列和異步隊列,js代碼是自上向下執行的,在主線程中當即執行的就是同步任務,好比簡單的邏輯操做及函數,而異步任務不會立馬立馬執行,會挪步放到到異步隊列中,好比ajax、promise、事件、計時器等等。ajax
也就是先執行同步,主線程結束後再按照異步的順序再次執行。promise
2、時間循環(Event Loop)異步
Event Loop是什麼?中文翻譯是事件循環,等待主線程中任務所有完成後,再回來把異步隊列中任務放到主程序中運行,這樣反覆的循環,就是事件循環。函數
先來看組代碼oop
console.log('開始111');spa
setTimeout(function() {線程
console.log('setTimeout111');翻譯
}, 0);
Promise.resolve().then(function() {
console.log('promise111');
}).then(function() {
console.log('promise222');
});
console.log('開始222');
咱們猜測一下上面的代碼,會怎樣打印?咱們知道,確定是先走同步的代碼,從上往下,先打印 「開始111」,再打印「開始222」。
中途的三個異步,進入到了異步隊列,等待同步執行完(打印完),返回來再執行異步,因此是後打印出來。
打印的結果先放一放,咱們稍後回來再說。如今咱們中途插播一段知識點:
3、宏觀任務和微觀任務(先執行微觀任務,再執行宏觀任務):
在事件循環中,每進行一次循環操做稱爲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'
);
咱們按照步驟來分析下:
一、遇到同步任務,直接先打印 「開始111」。
二、遇到異步 setTimeout ,先放到隊列中等待執行。
三、遇到了 Promise ,放到等待隊列中。
四、遇到同步任務,直接打印 「開始222」。
五、同步執行完,返回執行隊列中的代碼,從上往下執行,發現有宏觀任務 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');
分析一下:
一、遇到同步代碼,先打印 「開始111」 。
二、遇到setTimeout異步,放入隊列,等待執行 。
三、中途遇到Promise函數,函數直接執行,打印 「promise111」。
四、遇到setTimeout ,屬於異步,放入隊列,等待執行。
五、遇到Promise的then等待成功返回,異步,放入隊列。
六、遇到同步,打印 「開始222」。
七、執行完,返回,將異步隊列中的代碼,按順序執行。有一個微觀任務,then後的,因此打印 「promise222」,再執行兩個宏觀任務 「timeout111」 「timeout222」。
因此,打印的順序爲:開始111 、 promise111 、 開始222 、 promise222 、 timeout111 、 timeout222 .
先執行主任務,把異步任務放入循環隊列當中,等待主任務執行完,再執行隊列中的異步任務。異步任務先執行微觀任務,再執行宏觀任務。一直這樣循環,反覆執行,就是事件循環機制。