對于前段工程師來說,C/C++擴展模塊或許生成比較生疏和晦澀,但是如果你了解了它,在模塊出現性能瓶頸時將會對你有極大幫助。
JavaScript的一個典型弱點就是位運算。JavaScript的位運算參照Java的位運算實現,但是Java位運算是在int型數字的基礎上進行的,而JavaScript中只有double型的數據類型,在進行位運算的過程中,需要將double型轉換為int型,然后再進行。所以,在JavaScript層面上做位運算的效率并不高。
在應用中,會頻繁出現位運算的需求,包括轉碼、編碼等過程,如果通過JavaScript來實現,CPU資源將會耗費很多,這時編寫C/C++擴展模塊來提升性能的機會來了。
C/C++擴展模塊屬于文件模塊中的一類。前面講述文件模塊的編譯部分時提到,C/C++模塊通過預先編譯為.node文件,然后調用process.dlopen()方法加載執行。在這一節中,我們將分析整個C/C++擴展模塊的編寫、編譯、加載、導出的過程。
在開始編寫擴展模塊之前,需要強調的一點是,Node的原生模塊一定程度上是可以跨平臺的,其前提條件是源代碼可以支持在 `*nix` 和Windows上編譯,其中,`*nix`下通過g++/gcc等編譯器編譯為動態鏈接共享對象文件(.so),在Windows下則需要通過Visual C++ 的編譯器編譯為動態鏈接庫文件(.dll),如圖:

這里有一個讓人迷惑的地方,那就是引用加載時卻是.node文件。其實.node文件的擴展名只是為了看起來更自然一點,不會因為平臺差異產生不同的感覺。實際上,在Windows下它是一個.dll文件,在`*nix上`它是一個.so文件。為了實現跨平臺,dlopen()方法在內部實現時區分了平臺,分別用的是加載.so和.dll的方式。上圖中,為擴展模塊在不同平臺上編譯和加載的詳細過程。
值得注意的是,一個平臺下的.node文件在另一個平臺下是無法加載執行的,必須重新用各自平臺下的編譯器編譯為正確的.node文件。
- 目錄
- 第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 事件驅動與高性能服務器