
問題!
- JS 為什么是單線程的?
- 為什么需要異步?
- 單線程又是如何實現(xiàn)異步的呢?
- promise 的優(yōu)點是什么?
- 如何手動實現(xiàn)一個 Promise?
- async 做一件什么事情?
- await 在等什么?
- await 等到之后,做了一件什么事情?
- async/await 比 promise 有哪些優(yōu)勢?
js 是單線程的
js 是單線程的,所謂單線程,是指在 JS 引擎中負(fù)責(zé)解釋和執(zhí)行 JavaScript 代碼的線程只有一個, 有且只有一個調(diào)用棧,每次只能做一件事, 同一時間只能做一件事,瀏覽器渲染和 js 共用一個線程,不妨叫它主線程。之所以設(shè)計成這樣是為了避免 dom 渲染的沖突。
但是實際上還存在其他的線程。例如:處理 AJAX 請求的線程、處理 DOM 事件的線程、定時器線程、讀寫文件的線程(例如在 Node.js 中)等等。這些線程可能存在于 JS 引擎之內(nèi),也可能存在于 JS 引擎之外,在此我們不做區(qū)分。不妨叫它們工作線程。
但是 js 是需要異步操作的,比如 ajax 請求
通過 event loop 實現(xiàn)異步
為了支持異步操作,通過 event loop(事件循環(huán),事件輪詢)這種機(jī)制來實現(xiàn)異步
瀏覽器的 Event Loop 遵循的是 HTML5 標(biāo)準(zhǔn),而 NodeJs 的 Event Loop 遵循的是 libuv。
任務(wù)隊列
Js 中,有兩類任務(wù)隊列:宏任務(wù)隊列(macro tasks)和微任務(wù)隊列(micro tasks)。宏任務(wù)隊列可以有多個,微任務(wù)隊列只有一個。那么什么任務(wù),會分到哪個隊列呢?
宏任務(wù):script(全局任務(wù)), setTimeout, setInterval, setImmediate, I/O, UI rendering.
微任務(wù):process.nextTick, Promise, Object.observer, MutationObserver.
瀏覽器的執(zhí)行流程
當(dāng) call stack 空的時候,就會從任務(wù)隊列中,取任務(wù)來執(zhí)行。瀏覽器這邊,共分 3 步:
取一個宏任務(wù)來執(zhí)行。執(zhí)行完畢后,下一步。
取一個微任務(wù)來執(zhí)行,執(zhí)行完畢后,再取一個微任務(wù)來執(zhí)行。直到微任務(wù)隊列為空,執(zhí)行下一步。
更新 UI 渲染。
Event Loop 會無限循環(huán)執(zhí)行上面 3 步,這就是 Event Loop 的主要控制邏輯。其中,第 3 步(更新 UI 渲染)會根據(jù)瀏覽器的邏輯,決定要不要馬上執(zhí)行更新。畢竟更新 UI 成本大,所以,一般都會比較長的時間間隔,執(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");
(未完待續(xù)...)