根據這里整理所得
問題點
當前 Web Server 處理一個請求時多數時間被消耗在等待磁盤I/O及網絡延遲上
解決方案
比較傳統(tǒng)的解決方法是:程序員在編碼時開一個新的線程來處理需要消耗大量等待時間的操作。但這樣帶來的問題是更加程序復雜性度蜕该,對程序員編碼不友好凤跑。Node 通過基于事件輪詢的回調機制來解決該問題。
Node.js 事件輪詢
當程序調用了一段非阻塞的操作時惭适,Node 在低層開一個新的線程與主線程同時運行,一旦該隱藏線程的操作處理完成后,會將所得結果交由相應的回調函數處理。Node 通過 libuv 庫來處理異步 I/O 線程的調度問題昧捷。
任務隊列
javascript 是一種單線程、事件驅動的語言罐寨。所以需要通過事件的監(jiān)聽這種方式來處理多任務靡挥。即當事件被觸發(fā)時,程序調用事前提供的回調函數來處理該事件衩茸。而這些回調函數本身也能通過隊列來處理多任務芹血。
但我們只有一個主線程和一個回調棧,所以一個任務的回調函數需要等待執(zhí)行棧為空(即無任務--阻塞代碼在執(zhí)行)的時候才能執(zhí)行楞慈,從而形成了一個任務隊列幔烛。當主線程完成它的上一個任務時,可執(zhí)行的回調函數(如果有)總會被調起囊蓝,如此循環(huán)往復饿悬,故稱為事件輪詢。
微任務和大任務
Node 中包含兩種任務隊列來分別存放兩種類型的任務聚霜。
微任務包括:process.nextTick
, promises
, Object.observe
大任務包括:setTimeout
, setInterval
, setImmediate
, I/O
基于 WHATVG 規(guī)范狡恬,事件輪詢的一個周期只處理大任務隊列中的一個大任務。在這個周期內蝎宇,當大任務處理完成后弟劲,他下面微任務列表中可執(zhí)行的微任務才可以依次執(zhí)行。只有當該微任務隊列中的可執(zhí)行的微任務執(zhí)行完后姥芥,事件輪詢才可以進入下一個周期兔乞。
最后
在 async/await 尚未成為標準之前可通過 co 或者 koa 來處理異步操作的 callback hell 問題,當然也可以通過 async.js 來解決凉唐。