EventLoop 解決了什么問題(背景)?
JavaScript單線程是一門單線程的語言,同一個時間只能做一件事情蔬蕊,如果當一個語句需要執(zhí)行很長時間的話(比如:請求、定時器哥谷、讀取文件等等)岸夯,后面的語句就得一直等著前面的語句執(zhí)行結束后才會開始執(zhí)行。因此们妥,JavaScript將所有執(zhí)行任務分為了同步任務和異步任務猜扮。而Event Loop就是瀏覽器或Node解決JS單線程運行時不會阻塞的一種機制
什么是同步任務和異步任務
同步任務:又叫做非耗時任務,指的是在主線程上排隊執(zhí)行的那些任務监婶,只有前一個任務執(zhí)行完畢旅赢,才能執(zhí)行后一個任務
異步任務:又叫做耗時任務齿桃,異步任務由JavaScript 委托給宿主環(huán)境進行執(zhí)行,當異步任務執(zhí)行完成后煮盼,會通知JavaScript 主線程執(zhí)行異步任務的回調函數(shù)
什么是宏任務和微任務
JavaScript 把異步任務又做了進一步的劃分短纵,異步任務又分為兩類:宏任務和微任務
宏任務:當前調用棧執(zhí)行的任務
微任務:需要在此次宏任務執(zhí)行結束后,下一次宏任務執(zhí)行前僵控,執(zhí)行的任務
宏任務 | 微任務 |
---|---|
定時器(setTimeout香到、setInterval) | Promise(then、catch报破、finally) |
setImmediate | MutationObserver |
requestAnimationFrame | process.nextTick(Node) |
script標簽下整塊代碼 |
事件循環(huán)的進程模型
- 從宏任務隊列中悠就,按照入隊順序,找到第一個執(zhí)行的宏任務充易,放入調用棧理卑,開始執(zhí)行
- 執(zhí)行遇到異步任務,如果是微任務蔽氨,將放到微任務隊列中,如果是宏任務帆疟,則放到宏任務隊列中
- 同步任務執(zhí)行完成后(即調用棧清空后)鹉究,該宏任務被推出宏任務隊列,然后微任務隊列開始按照入隊順序踪宠,依次執(zhí)行其中的微任務自赔,直至微任務隊列清空為止
- 當微任務隊列清空后,一個事件循環(huán)結束
- 接著從宏任務隊列中柳琢,找到下一個執(zhí)行的宏任務绍妨,開始第二個事件循環(huán),直至宏任務隊列清空為止
常見面試題
// 整體代碼是一個宏任務柬脸,放入到宏任務隊列中他去,進入調用棧執(zhí)行
console.log(1);
setTimeout(()=>{
console.log(2);
Promise.resolve().then(res => { console.log(3) });
setTimeout(()=>{
console.log(4);
Promise.resolve().then(res => { console.log(5) });
}, 0)
}, 30)
Promise.resolve().then(res=>{ console.log(6) })
const fn = async () => {
console.log(7)
// 遇到了await 會等待promise完成,同時交出執(zhí)行權
await new Promise((resolve)=>{
// new Promise 中的代碼立即執(zhí)行
console.log(8)
setTimeout(()=>{
resolve();
console.log(9)
}, 20)
}).then(res => console.log(10));
console.log(11)
}
// fn執(zhí)行
fn();
setTimeout(()=>{
console.log(12);
new Promise((resolve) => {
console.log(13)
resolve();
}).then(res => { console.log(14) })
}, 0)
// 打印結果:1 7 8 6 12 13 14 9 10 11 2 3 4 5