JavaScript同步任務與異步任務執(zhí)行順序
點擊上方藍色字體,選擇“標星公眾號”
優(yōu)質文章,第一時間送達
JavaScript是單線程執(zhí)行的,即 js 中任務是按順序依次執(zhí)行的,但若其中一個任務執(zhí)行時間過長,后續(xù)任務會一直等待,造成程序假死。為了解決這個問題,將任務分為同步任務和異步任務,其中異步任務又分為宏任務和微任務。
同步任務與異步任務:
同步任務:又叫做非耗時任務,指的是在主線程上排隊執(zhí)行的那些任務
? ?只有前一個任務執(zhí)行完畢,才能執(zhí)行后一個任務
異步任務:又叫做耗時任務,異步任務由JavaScript 委托給宿主環(huán)境進行執(zhí)行?
當異步任務執(zhí)行完成后,會通知JavaScript 主線程執(zhí)行異步任務的回調函數(shù)

同步任務由JavaScript主線程次序執(zhí)行
異步任務委托給宿主環(huán)境執(zhí)行
已完成的異步任務對應的回調函數(shù),會被加入到任務隊列中等待執(zhí)行
JavaScript 主線程執(zhí)行棧被清空后會讀取任務隊列中的回調函數(shù),次序執(zhí)行
JavaScript 主線程不斷重復上面的第4步
JavaScript主線程從“任務隊列”中讀取異步任務的回調函數(shù),放到執(zhí)行棧中依次執(zhí)行。這個過程是循環(huán)不斷的,所以整個的這種運行機制又稱為 EventLoop (事件循環(huán))
宏任務與微任務
宏任務:異步Ajax請求,setTimeout,setInterval,文件操作,new Promise等
微任務:Promise.then、.catch、.finally,process.nextTick等

?
宏任務與微任務是交替執(zhí)行的,每次執(zhí)行完宏任務都會檢查是否有微任務
代碼示例:
console.log('A');
setTimeout(function()?{
??console.log('B');
},?0);
Promise.resolve().then(function()?{
??console.log('C');
}).then(function()?{
??console.log('D');
});
console.log('E');先執(zhí)行同步任務打印A和E,再執(zhí)行異步任務中的微任務,打印C和D,最后執(zhí)行宏任務打印B
最終打印結果:AECDB
可能有人會問,為什么微任務優(yōu)先于宏任務執(zhí)行,其實并不是,這里先執(zhí)行微任務的原因是,script本身也是一個宏任務,這個宏任務執(zhí)行結果就是添加各種微任務與宏任務,比如下面代碼中,同步任務執(zhí)行完成后,會先執(zhí)行script的宏任務,即添加一個setTimeout的宏任務與一個Promise.then的微任務,這個宏任務執(zhí)行完成后,就該執(zhí)行Promise.then的微任務了。并不是微任務優(yōu)先級大于宏任務,而是這個宏任務執(zhí)行感知不強,會讓人感覺并沒有執(zhí)行宏任務,其實是同樣遵循上面流程,執(zhí)行了宏任務
下面是一個多層次代碼,可進行練習:
?1?console.log('1')
?2?
?3?setTimeout(function?()?{
?4???console.log('2')
?5???process.nextTick(function?()?{
?6?????console.log('3')
?7???})
?8???new?Promise(function?(resolve)?{
?9?????console.log('4')
10?????resolve()
11???}).then(function?()?{
12?????console.log('5')
13???})
14?})
15?Promise.resolve().then(function?()?{
16???console.log('6')
17?})
18?new?Promise(function?(resolve)?{
19???console.log('7')
20???resolve()
21?}).then(function?()?{
22???console.log('8')
23?})
24?
25?setTimeout(function?()?{
26???console.log('9')
27???process.nextTick(function?()?{
28?????console.log('10')
29???})
30???new?Promise(function?(resolve)?{
31?????console.log('11')
32?????resolve()
33???}).then(function?()?{
34?????console.log('12')
35???})
36?})分析:
第一遍:
首先執(zhí)行第一行的同步任務,打印1
第三行的setTimeout是異步任務中宏任務,加入宏任務記為setTimeout1
下面第15行Promise.then是異步任務中的微任務,加入微任務記為 then
第18行new Promise是同步任務,執(zhí)行第一個log直接打印7,后面的 .then 是微任務,存入微任務中記為 then1
第25行setTimeout是異步任務中宏任務,加入宏任務記為 setTimeout2
此時整個程序狀態(tài)如下:

第二遍:
首先執(zhí)行微任務區(qū)中的任務,then打印6,then1打印8
微任務區(qū)任務執(zhí)行完成,再執(zhí)行宏任務區(qū) setTimeout1 ,打印2,將第5行process微任務放入微任務區(qū)記作 process2
第8行new Promise為同步任務,立即執(zhí)行打印4,將后續(xù) .then 微任務?放入微任務區(qū)記作 then2
此時整個程序狀態(tài)如下:

第三遍:
首先執(zhí)行微任務區(qū),process2,打印3,再執(zhí)行then2,打印5?
微任務區(qū)執(zhí)行完成,再去執(zhí)行宏任務區(qū)中的setTimeout2,首先是第26行l(wèi)og直接打印9
將第27行process微任務放入微任務區(qū)記作 process3
第30行new Promise為同步任務,立即執(zhí)行打印11,將后續(xù) .then 微任務?放入微任務區(qū)記作 then3
此時整個程序狀態(tài)如下:
最后一遍:
執(zhí)行微任務區(qū)process3,打印10
執(zhí)行微任務區(qū)then3,打印12
最終打印結果:1,7,6,8,2,4,3,5,9,11,10,12
? 作者?|??mmsmd
來源 |??cnblogs.com/mmsmd/p/15370669.html

