您好,登錄后才能下訂單哦!
這篇文章主要講解了“怎么進行Node.js擴展開發(fā)”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“怎么進行Node.js擴展開發(fā)”吧!
1.Node.js不適合cpu密集型業(yè)務,開發(fā)擴展使用libuv線程池做異步計算
2.需要更高的執(zhí)行性能,例如使用c++、Rust等比javascript更高效的語言
3.已有c++庫,直接封裝成Node.js擴展提供給javascript調用,避免重復開發(fā)
4.通過javascript無法實現(xiàn)的能力,開發(fā)擴展增強Node.js能力
Node.js擴展是文件擴展名為.node的二進制文件,本質上是動態(tài)鏈接庫,可以理解為改了名的.dll或.so文件,可以被require加載
Node.js module官方文檔 nodejs.cn/api/modules…
擴展類型 | 基本描述 | Node.js版本變化時改代碼 | Node.js版本變化時重新編譯 |
---|---|---|---|
直接寫C++ | 直接引用v8、libuv等庫進行開發(fā) | 是 | 是 |
NAN | 使用NAN(Native Abstraction for Node.js)進行開發(fā) | 否 | 是 |
N-API | 使用node-addon-api進行開發(fā) | 否(ABI版本需一致) | 否(ABI版本需一致) |
直接寫C++代碼開發(fā)插件,當Node.js版本變化時引用的v8、libuv等庫的版本可能發(fā)生變化,這些三方庫的api也可能會變化,導致需要修改代碼 NAN方式開發(fā)插件,引用nan.h需要在Node.js版本變化時重新編譯 N-API方式調用Node.js穩(wěn)定的二進制ABI接口(Application Binary Interface),只要ABI版本號一致就不需要重新編譯復制代碼
我們可以從Node.js官網(wǎng)歷史版本下載頁面,NODE_MODULE_VERSION看到Node.js版本與ABI版本的對應關系,nodejs.org/zh-cn/downl…
或者執(zhí)行process.versions.modules查看ABI版本;process.versions查看相關配套版本:
> process.versions { node: '18.0.0', v8: '10.1.124.8-node.13', uv: '1.43.0', zlib: '1.2.11', brotli: '1.0.9', ares: '1.18.1', modules: '108', nghttp2: '1.47.0', napi: '8', llhttp: '6.0.4', openssl: '3.0.2+quic', cldr: '41.0', icu: '71.1', tz: '2022a', unicode: '14.0', ngtcp2: '0.1.0-DEV', nghttp3: '0.1.0-DEV' }
我們來看下官方的Node.js擴展代碼示例:github.com/nodejs/node… 對于N-API方式來說,c語言對應示例代碼中的napi案例,c++對應示例代碼中的node-addon-api案例,引用的頭文件不同。
首先,需要安裝依賴,按官方的說法可以使用windows-build-tools安裝所有依賴。 nodejs.cn/api/n-api.h…
但是,公司內網(wǎng)環(huán)境一直安裝失敗,按照文檔嘗試改了各種參數(shù)還是失敗,可能是公司內網(wǎng)環(huán)境問題。如果你也遇到類似問題,可以嘗試手動安裝依賴。 github.com/felixrieseb…
手動安裝步驟如下:
1.安裝node-gyp
npm install -g node-gyp
2.安裝Visual Studio Build Tools
安裝完成后更新npm配置,例如我安裝的版本號是2022
npm config set msvs_version 2022
安裝headers,頭文件和Node.js版本是對應的,如果用nvm等工具切換過Node.js版本,請重新安裝
node-gyp install --dist-url=http://mirrors.tools.huawei.com/Node.js/
此步驟會將node_api.h等頭文件下載到本地,按Node.js版本號區(qū)分目錄,例如:
C:\Users\z00443016\AppData\Local\node-gyp\Cache\18.0.0\include\node
配置IDE時會需要用到,當前可以忽略,后續(xù)的文章會再介紹具體配置
3.安裝python
安裝完成后將python和python/Scripts/目錄加入到Path環(huán)境變量
更新npm配置,
npm config set python D:\runtime\python復制代碼
以c++開發(fā)為例,復制官網(wǎng)示例到本地。github.com/nodejs/node…
執(zhí)行npm install會自動調用node-gyp編譯,生成build/Release/hello.node的目標文件,這個文件就是最終被js引用的擴展包,可以被require調用。
執(zhí)行示例文件中的hello.js,會調用hello.cc中定義的hello方法輸出'world'。
var addon = require('bindings')('hello'); // 或者直接require hello.node文件 // var addon = require('./build/Release/hello.node'); console.log(addon.hello()); // 'world'
如需重新編譯,可以執(zhí)行node-gyp rebuild,或者執(zhí)行node-gyp help了解其他命令
至此,一個Node.js擴展demo就完成了。
Node.js使用非阻塞io的方式,在一個線程內可以異步處理多個任務,但是如果有一個cpu密集型的任務一直在處理,那么就會阻塞其他任務,響應時間變長。
Node.js官網(wǎng)的解釋如下 nodejs.cn/learn/the-n…
開發(fā)Node.js擴展是解決問題的方式之一,最終使用什么方式去解決問題,需要基于我們對Node.js的理解,找到最佳實踐。在上述場景中,我們可以使用libuv提供的線程池來異步處理這些cpu消耗較高的任務,從而不會阻塞其他任務的執(zhí)行。
當然了,web server并不適合處理cpu密集型任務,如果這個cpu密集型的任務調用頻繁且耗時較高,就需要考慮從業(yè)務維度拆分,將任務挪到消息隊列消費端執(zhí)行。
vsCode安裝c++ intelliSense擴展應用
配置.vscode/c_cpp_properties.json,主要在includePath中配置好headers路徑
{ "configurations": [ { "name": "Win32", "includePath": [ "${workspaceFolder}/**", "C:\Users\${userName}\AppData\Local\node-gyp\Cache\18.0.0\include\node", "D:\tool\nvm\v18.0.0\node_global\node_modules\node-addon-api" ], "defines": [ "_DEBUG", "UNICODE", "_UNICODE" ], "cStandard": "c17", "cppStandard": "c++17", "intelliSenseMode": "windows-msvc-x64" } ], "version": 4 }
配置.vscode/launch.json,完成調試配置就可以斷點調試了。
{ "version": "0.2.0", "configurations": [ { "name": "c++ launch", "type": "lldb", "request": "launch", "program": "D:\runtime\nodejs\node.exe", "args": ["${workspaceFolder}/src/hello.js"], "stopAtEntry": true, "cwd": "${fileDirname}", "environment": [], "externalConsole": true, "MIMode": "lldb", "setupCommands": [ { "description": "為 gdb 啟用整齊打印", "text": "-enable-pretty-printing", "ignoreFailures": true } ] } ] }
可以參考官網(wǎng)示例,在項目中的Execute方法中添加自定義代碼,不妨動手一式。github.com/nodejs/node…
node-gyp是Node.js擴展的構建工具,依賴python和Visual Studio Build Tools,基于google的gyp(Generate Your Projects)工具,chromium、v8等項目也在使用gyp構建。還可以使用CMake.js等工具進行編譯構建。
npm config set msvs_version 2022 npm config set python D:\runtime\python
在package.json中定義"gypfile": true,執(zhí)行npm install時會自動調用ndoe-gyp執(zhí)行build操作。github.com/nodejs/node…
{ "name": "hello_world", "version": "0.0.0", "description": "Node.js Addons Example #1", "main": "hello.js", "private": true, "dependencies": { "bindings": "~1.2.1", "node-addon-api": "^1.0.0" }, "scripts": { "test": "node hello.js" }, "gypfile": true }
由于編譯是基于操作系統(tǒng)和硬件平臺進行的,node-gyp構建生成的.node動態(tài)鏈接庫不能跨平臺,所以通常我們在使用Node.js擴展時以依賴包的形式引入項目,當執(zhí)行npm install時,自動調用node-gyp生成當前環(huán)境可用的.node擴展包。
上述方式需要即時編譯,無疑會拖慢npm install過程。于是就出現(xiàn)了node-pre-gyp預構建工具,直接從倉庫下載當前環(huán)境可用的Node.js擴展包。
以Xprofiler為例,根據(jù)當前系統(tǒng)、硬件平臺、Node.js的ABI版本生成下載地址,定義在package.json的binary字段:
"binary": { "module_name": "xprofiler", "module_path": "./build/binding/{configuration}/{node_abi}-{platform}-{arch}/", "remote_path": "./v{version}/", "package_name": "{module_name}-v{version}-{node_abi}-{platform}-{arch}.tar.gz", "host": "https://github.com/X-Profiler/xprofiler/releases/download" },
mirrors.tools.huawei.com/xprofiler/v…
rust語言非?;鸨贜ode.js開發(fā)領域也大有成為基礎設施的趨勢。比如,Node.js作者的新項目Deno就是用rust語言開發(fā)的;使用swc開發(fā)的編譯工具替代Babel提升性能;rust支持編譯成Webassembly,在前后臺都能執(zhí)行,具有很好的前景。
很多公司對rust語言十分重視,例如下圖中的TOP公司已經(jīng)成為rust基金會白金會員,用實際行動支持rust語言的發(fā)展。foundation.rust-lang.org/
類似c++項目使用napi開發(fā)Node.js擴展,社區(qū)出現(xiàn)了napi-rs項目來支持rust語言開發(fā)Node.js擴展。github.com/napi-rs/nap…
FFI(Foreign Function Interface)語言交互接口,用一種編程語言寫的程序能調用另一種編程語言寫的函數(shù),基本上成熟的編程語言都支持。使得我們可以在Node.js中直接調用c/c++、go、rust等語言編譯生成的動態(tài)鏈接庫,示例如下: github.com/node-ffi/no…
例如libmylibrary.dll或libmylibrary.so動態(tài)鏈接庫的代碼,c語言中的.h頭文件描述:
double do_some_number_fudging(double a, int b); myobj * create_object(); double do_stuff_with_object(myobj *obj); void use_string_with_object(myobj *obj, char *value); void delete_object(myobj *obj);
js中使用ffi進行對應描述:
var ffi = require("ffi"); var MyLibrary = ffi.Library('libmylibrary', { "do_some_number_fudging": [ 'double', [ 'double', 'int' ] ], "create_object": [ myobjPtr, [] ], "do_stuff_with_object": [ "double", [ myobjPtr ] ], "use_string_with_object": [ "void", [ myobjPtr, "string" ] ], "delete_object": [ "void", [ myobjPtr ] ] });
然后,就可以在js中調用了:
var res = MyLibrary.do_some_number_fudging(1.5, 5); var fun_object = MyLibrary.create_object(); if (fun_object.isNull()) { console.log("Oh no! Couldn't create object!\n"); } else { MyLibrary.use_string_with_object(fun_object, "Hello World!"); var fun = MyLibrary.do_stuff_with_object(fun_object); MyLibrary.delete_object(fun_object); }
感謝各位的閱讀,以上就是“怎么進行Node.js擴展開發(fā)”的內容了,經(jīng)過本文的學習后,相信大家對怎么進行Node.js擴展開發(fā)這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內容。