組裝好請求對象、送入I/O線程池等待執行,實際上完成了異步I/O的第一部分,回調通知是第二部分。
線程池中的I/O操作調用完畢之后,會將獲取的結果儲存在req->result屬性上,然后調用PostQueuedCompletionStatus()通知IOCP,告知當前對象操作已經完成:
~~~
PostQueuedCompletionStatus((loop)->iocp, 0, 0, &((req)->overlapped))
~~~
PostQueuedCompletionStatus()方法的作用是向IOCP提交執行狀態,并將線程歸還線程池。通過PostQueuedCompletionStatus()方法提交的狀態,可以通過GetQueuedCompletionStatus()提取。
在這個過程中,我們其實還動用了事件循環的I/O觀察者。在每次Tick的執行中,它會調用IOCP相關的GetQueuedCompletionStatus()方法檢查線程池中是否有執行完的請求,如果存在,會將請求對象加入到I/O觀察者的隊列中,然后將其當作事件處理。
I/O觀察者回調函數的行為就是取出請求對象的result屬性作為參數,取出oncomplete_sym屬性作為方法,然后調用執行,以此達到調用JavaScript中傳入的回調函數的目的。
至此,整個異步I/O的流程完全結束,如圖:

事件循環、觀察者、請求對象、I/O線程池這4者共同構成了Node異步I/O模型的基本要素。
Windows下主要通過IOCP來向系統內核發送I/O調用和從內核獲取已完成的I/O操作,配以事件循環,以此完成異步I/O的過程。在Linux下通過epoll實現了這個過程,FreeBSD下通過kqueue實現,Solaris下通過Event ports實現。不同的是線程池在Windows下由內核(IOCP)直接提供,`*nix`系列下由libuv自行實現。
- 目錄
- 第1章 Node 簡介
- 1.1 Node 的誕生歷程
- 1.2 Node 的命名與起源
- 1.2.1 為什么是 JavaScript
- 1.2.2 為什么叫 Node
- 1.3 Node給JavaScript帶來的意義
- 1.4 Node 的特點
- 1.4.1 異步 I/O
- 1.4.2 事件與回調函數
- 1.4.3 單線程
- 1.4.4 跨平臺
- 1.5 Node 的應用場景
- 1.5.1 I/O 密集型
- 1.5.2 是否不擅長CPU密集型業務
- 1.5.3 與遺留系統和平共處
- 1.5.4 分布式應用
- 1.6 Node 的使用者
- 1.7 參考資源
- 第2章 模塊機制
- 2.1 CommonJS 規范
- 2.1.1 CommonJS 的出發點
- 2.1.2 CommonJS 的模塊規范
- 2.2 Node 的模塊實現
- 2.2.1 優先從緩存加載
- 2.2.2 路徑分析和文件定位
- 2.2.3 模塊編譯
- 2.3 核心模塊
- 2.3.1 JavaScript核心模塊的編譯過程
- 2.3.2 C/C++核心模塊的編譯過程
- 2.3.3 核心模塊的引入流程
- 2.3.4 編寫核心模塊
- 2.4 C/C++擴展模塊
- 2.4.1 前提條件
- 2.4.2 C/C++擴展模塊的編寫
- 2.4.3 C/C++擴展模塊的編譯
- 2.4.2 C/C++擴展模塊的加載
- 2.5 模塊調用棧
- 2.6 包與NPM
- 2.6.1 包結構
- 2.6.2 包描述文件與NPM
- 2.6.3 NPM常用功能
- 2.6.4 局域NPM
- 2.6.5 NPM潛在問題
- 2.7 前后端共用模塊
- 2.7.1 模塊的側重點
- 2.7.2 AMD規范
- 2.7.3 CMD規范
- 2.7.4 兼容多種模塊規范
- 2.8 總結
- 2.9 參考資源
- 第3章 異步I/O
- 3.1 為什么要異步I/O
- 3.1.1 用戶體驗
- 3.1.2 資源分配
- 3.2 異步I/O實現現狀
- 3.2.1 異步I/O與非阻塞I/O
- 3.2.2 理想的非阻塞異步I/O
- 3.2.3 現實的異步I/O
- 3.3 Node的異步I/O
- 3.3.1 事件循環
- 3.3.2 觀察者
- 3.3.3 請求對象
- 3.3.4 執行回調
- 3.3.5 小結
- 3.4 非I/O的異步API
- 3.4.1 定時器
- 3.5 事件驅動與高性能服務器