根據(jù)這里整理所得
問題點(diǎn)
當(dāng)前 Web Server 處理一個(gè)請求時(shí)多數(shù)時(shí)間被消耗在等待磁盤I/O及網(wǎng)絡(luò)延遲上
解決方案
比較傳統(tǒng)的解決方法是:程序員在編碼時(shí)開一個(gè)新的線程來處理需要消耗大量等待時(shí)間的操作。但這樣帶來的問題是更加程序復(fù)雜性度,對程序員編碼不友好。Node 通過基于事件輪詢的回調(diào)機(jī)制來解決該問題。
Node.js 事件輪詢
當(dāng)程序調(diào)用了一段非阻塞的操作時(shí),Node 在低層開一個(gè)新的線程與主線程同時(shí)運(yùn)行,一旦該隱藏線程的操作處理完成后,會(huì)將所得結(jié)果交由相應(yīng)的回調(diào)函數(shù)處理。Node 通過 libuv 庫來處理異步 I/O 線程的調(diào)度問題。
任務(wù)隊(duì)列
javascript 是一種單線程、事件驅(qū)動(dòng)的語言。所以需要通過事件的監(jiān)聽這種方式來處理多任務(wù)。即當(dāng)事件被觸發(fā)時(shí),程序調(diào)用事前提供的回調(diào)函數(shù)來處理該事件。而這些回調(diào)函數(shù)本身也能通過隊(duì)列來處理多任務(wù)。
但我們只有一個(gè)主線程和一個(gè)回調(diào)棧,所以一個(gè)任務(wù)的回調(diào)函數(shù)需要等待執(zhí)行棧為空(即無任務(wù)--阻塞代碼在執(zhí)行)的時(shí)候才能執(zhí)行,從而形成了一個(gè)任務(wù)隊(duì)列。當(dāng)主線程完成它的上一個(gè)任務(wù)時(shí),可執(zhí)行的回調(diào)函數(shù)(如果有)總會(huì)被調(diào)起,如此循環(huán)往復(fù),故稱為事件輪詢。
微任務(wù)和大任務(wù)
Node 中包含兩種任務(wù)隊(duì)列來分別存放兩種類型的任務(wù)。
微任務(wù)包括:process.nextTick, promises, Object.observe
大任務(wù)包括:setTimeout, setInterval, setImmediate, I/O
基于 WHATVG 規(guī)范,事件輪詢的一個(gè)周期只處理大任務(wù)隊(duì)列中的一個(gè)大任務(wù)。在這個(gè)周期內(nèi),當(dāng)大任務(wù)處理完成后,他下面微任務(wù)列表中可執(zhí)行的微任務(wù)才可以依次執(zhí)行。只有當(dāng)該微任務(wù)隊(duì)列中的可執(zhí)行的微任務(wù)執(zhí)行完后,事件輪詢才可以進(jìn)入下一個(gè)周期。

最后
在 async/await 尚未成為標(biāo)準(zhǔn)之前可通過 co 或者 koa 來處理異步操作的 callback hell 問題,當(dāng)然也可以通過 async.js 來解決。