單線程異步
js是單線程異步的,單線程就是同一時間只做一件事,原因是避免dom操作的沖突,設想一下js是多線程的,然后多線程上的js都要操作一個dom,就會產生沖突。而僅僅是單線程的話,如果有一個請求要耗費很長時間時,瀏覽器就會卡在那里等待,這樣當然也不行,所以有了異步。
event-loop
那么異步要怎么運行?這就是接下來要說的event-loop(事件輪詢)
event-loop是js的運行機制,其執(zhí)行的方式如下:

1.同步和異步任務分別進入不同的執(zhí)行"場所",同步的進入主線程,異步的進入Event Table并注冊函數(shù)。
2.當指定的事情完成時,Event Table會將這個函數(shù)移入Event Queue。
3.主線程內的任務執(zhí)行完畢為空,會去Event Queue讀取對應的函數(shù),進入主線程執(zhí)行。
4.上述過程會不斷重復,也就是常說的Event Loop(事件循環(huán))。
除了廣義的同步任務和異步任務,我們對任務有更精細的定義:
macro-task(宏任務):包括整體代碼script,setTimeout,setInterval
micro-task(微任務):Promise,process.nextTick
注意:任務隊列分微任務和宏任務,先執(zhí)行全部的微任務,再執(zhí)行宏任務。
接下來看一下下面的案例:
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
async1();
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
console.log('script end');
分析:
1、整個代碼塊作為一個宏任務,進入主線程,async1和async2函數(shù)定義,遇到console.log輸出script start;
2、遇到setTimeout() ,把它的回調函數(shù)放入宏任務(setTimeout1)。
| 微任務 | 宏任務 |
|---|---|
| setTimeout1 |
3、遇到執(zhí)行async1(), 執(zhí)行async1,遇到console.log輸出async1 start;
4、然后遇到await async2(),執(zhí)行async2();
5、看到console.log輸出async2,之后沒有返回值,結束函數(shù),返回undefined,返回到async1的執(zhí)行上下文的await undefined,由于async函數(shù)使用await后得語句會被放入一個回調函數(shù)中,所以把下面的放入微任務中。
| 微任務 | 宏任務 |
|---|---|
| async1=> await后面的語句 | setTimeout1 |
6、結束async1,返回全局上下文,遇到Promise構造函數(shù),里面的執(zhí)行函數(shù)立馬執(zhí)行, 輸出promise1, 之后的回調函數(shù)進入微任務;
| 微任務 | 宏任務 |
|---|---|
| async1=> await后面的語句 | setTimeout1 |
| new Promise() => 后的then |
執(zhí)行完Promise(),遇到console.log,輸出script end,這里一個宏任務代碼塊執(zhí)行完畢。
7、主線程現(xiàn)在空閑下來后,執(zhí)行事件隊列中的微任務,遇到new Promise()后面的回調函數(shù),執(zhí)行代碼,輸出promise2(這里2個微任務的優(yōu)先級,promise高于async)。
8、看到async1中await后面的回調函數(shù),執(zhí)行代碼,輸出async1 end
9、此時微任務中的隊列為空,開始執(zhí)行隊列中的宏任務,遇到console.log,輸出setTimeout。
最后,執(zhí)行完成,最后結果為
script start
async1 start
async2
promise1
script end
promise2
async1 end
setTimeout