编写原生的Node.js模块
通常,我們開發原生Node.js模塊包括但不僅限于以下原因:
-
對性能有比較苛刻要求的應用。盡管Node.js得益于libuv,在異步I/O操作很有優勢,但遇到數字計算時并不是一個很好的選擇。
-
使用更加底層的API,比如操作系統層面的。
-
在C/C++和Node.js之間創建一個Bridge,進行通信。
什么是原生模塊?
Node.js Addons是動態鏈接的可共享對象,由C/C++編寫而成。可以在Node.js中通過require()方法進行調用,使用起來像調用Node.js普通模塊一樣。 —— 來自Node.js官方文檔
這意味著如果處理得當的話,模塊調用者使用由C/C++編寫的原生模塊的方式和由Node.js編寫的模塊一樣。想要編寫Node.js addons,你需要了解一些基本知識:
-
Libuv
-
V8
-
Node.js internals
推薦閱讀這些資料。
創建Node.js的原生擴展模塊
下面我以一個常見的動態規劃問題-青蛙跳臺階為例子來說明如何創建一個原生的Node.js模塊。青蛙跳臺階描述為:一只青蛙一次可以跳上一級臺階,也可以跳上2級臺階,求該青蛙跳上n級臺階的共有多少種跳法?
首先創建一個frog_jump.cc原生文件,.cc的意思是c with class,擴展名也可以是.cpp。Google Style Guide建議使用.cc,那么此處還是以.cc做為擴展名吧。代碼如下:
#include?<node.h>#include<vector>/***?Native?method,?calculate?all?ways?frog?jump?to?a?target?stair.*/int?climbStairs(int?n)?{??std::vector<int>?dp(n);dp[1]?=?1;dp[2]?=?2;??for?(int?i?=?3;?i?<=?n;?i?++?)?{dp[i]?=?dp[i?-?1]?+?dp[i?-?2];}??return?dp[n]; }/***?Export?native?method?jumpTo*/void?JumpTo(const?v8::FunctionCallbackInfo<v8::Value>&?args)?{v8::Isolate*?isolate?=?args.GetIsolate();??//?Check?input?typeif?(!args[0]?->?IsNumber())?{isolate?->?ThrowException(v8::Exception::TypeError(v8::String::NewFromUtf8(isolate,?"Wrong?arguments?type!")));}??int?value?=?climbStairs(args[0]?->?NumberValue());v8::Local<v8::Number>?num?=?v8::Number::New(isolate,?value);args.GetReturnValue().Set(num); }//?init?is?entry?point.void?init(v8::Local<v8::Object>?exports)?{NODE_SET_METHOD(exports,?"jumpTo",?JumpTo); }NODE_MODULE(frog_jump,?init)對這段代碼的解釋:
-
#include "node.h" 是c++里面引入頭文件的方式,具體源碼:node.h,C++鏈接時會加載這個頭文件。頭文件里面引入了v8命名空間,我們可以通過v8::標志來訪問v8的接口。訪問所有v8的類型,都需要使用v8::標志
-
通過args對象來訪問Node.js傳遞過來的參數,通過args也可以獲取調用相關信息。
-
通過v8::Isolate*可以獲取函數作用域,可以像JS里面一樣進行變量賦值,而不用擔心垃圾回收問題,垃圾回收器會自動進行。
-
args.GetReturnValue()可以對函數返回的結果進行設置。
-
任何原生Node.js模塊都需要調用NODE_MODULE,NODE_MODULE是一個宏,它會進行模塊注冊操作。
-
C++ 有豐富的內置類型來保存數字或者字符串,但是JS只能識別v8::里面定義的類型。因此,將c++的變量賦值給JS時,需要轉換成可以被JS識別的類型,也即是v8::定義的類型。比如v8::String、v8::Object。
編譯原生的Node.js模塊
一旦源代碼編寫完成,需要將它編譯成二進制的addon.node文件,之后才能被Node.js require。為了完成編譯操作,需要在項目的根目錄創建binding.gyp文件,里面定義了Build的配置。binding.gyp的內容是一個JSON。
{"targets":?[{"target_name":?"frog_jump","sources":?[?"frog_jump.cc"?]}] }編譯環境配置:
-
windows: 以管理員的身份運行npm install --global --production windows-build-tools,這個會安裝所有編譯依賴的工具。
-
linux: 安裝python?v2.7、make和GCC
-
osx: 安裝xcode
雖然npm內置了一個node-gyp版本,但是這個版本沒有開放給開發者進行調用。npm install的時候會調用它來進行編譯和安裝工作。因此,開發者想要調用node-gyp必須自己安裝一個全局的node-gyp版本。
$?npm?install?node-gyp?-g $?node-gyp?configure $?node-gyp?build運行node-gyp configure命令會生成一個跨平臺的build文件,unix環境會生成Makefile,windows環境會在build目錄里面生成vcxproj。
運行node-gyp build命令會生成可被Node.js調動的addon.node二進制文件。
Node.js中調用原生模塊
const?frogJump?=?require('./build/Release/frog_jump');frogJump.jumpTo(20);??//青蛙跳到第20個臺階的所有方法本文轉自xsster51CTO博客,原文鏈接:http://blog.51cto.com/12945177/1932206 ,如需轉載請自行聯系原作者
總結
以上是生活随笔為你收集整理的编写原生的Node.js模块的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Oracle全球裁员潮:云计算成趋势
- 下一篇: 瓜子二手车:二手车大流通新政1年,推动二