Comment réaliser le développement de l'extension Node ? L'article suivant présentera les connaissances préalables au développement d'extensions Node.js et vous aidera à démarrer avec le développement d'extensions Node.js. J'espère qu'il sera utile à tout le monde !
1.Node.js ne convient pas aux activités gourmandes en CPU L'extension de développement utilise un pool de threads libuv pour le calcul asynchrone
2. , Par exemple, utilisez C++, Rust et d'autres langages plus efficaces que Javascript
3 Les bibliothèques C++ existantes sont directement encapsulées dans les extensions Node.js pour les appels javascript afin d'éviter un développement répété
4. ne peut pas être réalisé grâce aux capacités javascript de Node.js
L'extension Node.js est un fichier binaire avec l'extension de fichier .node. Il s'agit essentiellement d'une bibliothèque de liens dynamiques, qui peut être comprise comme un fichier binaire. renommé .dll ou .so Fichier, peut être chargé par require
Document officiel du module Node.jsnodejs.cn/api/modules...
Type d'extension | Description de base | Changer le code lorsque la version de Node.js change | Recompiler lorsque la version de Node.js change |
---|---|---|---|
Écrire directement en C++ | Référencer directement v8, libuv et d'autres bibliothèques pour développement | Oui | Oui |
NAN | Utiliser NAN (Native Abstraction for Node.js) pour le développement | Non | Oui |
N-API | Utiliser node-addon-api pour le développement | Non (les versions ABI doivent être cohérentes) | Non (les versions ABI doivent être cohérentes) |
直接写C++代码开发插件,当Node.js版本变化时引用的v8、libuv等库的版本可能发生变化,这些三方库的api也可能会变化,导致需要修改代码 NAN方式开发插件,引用nan.h需要在Node.js版本变化时重新编译 N-API方式调用Node.js稳定的二进制ABI接口(Application Binary Interface),只要ABI版本号一致就不需要重新编译复制代码
我们可以从Node.js官网历史版本下载页面,NODE_MODULE_VERSION看到Node.js版本与ABI版本的对应关系,nodejs.org/zh-cn/downl…
或者执行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…
但是,公司内网环境一直安装失败,按照文档尝试改了各种参数还是失败,可能是公司内网环境问题。如果你也遇到类似问题,可以尝试手动安装依赖。 github.com/felixrieseb…
手动安装步骤如下:
1.安装node-gyp
npm install -g node-gyp
2.安装Visual Studio Build Tools
可以参考node-gyp文档中的下载链接和步骤进行安装github.com/nodejs/node…
安装完成后更新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版本号区分目录,例如:
C:\Users\z00443016\AppData\Local\node-gyp\Cache\18.0.0\include\node
配置IDE时会需要用到,当前可以忽略,后续的文章会再介绍具体配置
3.安装python
官网下载地址:www.python.org/downloads/
安装完成后将python和python/Scripts/目录加入到Path环境变量
更新npm配置,
npm config set python D:\runtime\python复制代码
以c++开发为例,复制官网示例到本地。github.com/nodejs/node…
执行npm install会自动调用node-gyp编译,生成build/Release/hello.node的目标文件,这个文件就是最终被js引用的扩展包,可以被require调用。
执行示例文件中的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'
如需重新编译,可以执行node-gyp rebuild,或者执行node-gyp help了解其他命令
至此,一个Node.js扩展demo就完成了。
Node.js使用非阻塞io的方式,在一个线程内可以异步处理多个任务,但是如果有一个cpu密集型的任务一直在处理,那么就会阻塞其他任务,响应时间变长。
Node.js官网的解释如下 nodejs.cn/learn/the-n…
开发Node.js扩展是解决问题的方式之一,最终使用什么方式去解决问题,需要基于我们对Node.js的理解,找到最佳实践。在上述场景中,我们可以使用libuv提供的线程池来异步处理这些cpu消耗较高的任务,从而不会阻塞其他任务的执行。
当然了,web server并不适合处理cpu密集型任务,如果这个cpu密集型的任务调用频繁且耗时较高,就需要考虑从业务维度拆分,将任务挪到消息队列消费端执行。
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 } ] } ] }
可以参考官网示例,在项目中的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,执行npm install时会自动调用ndoe-gyp执行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 }
由于编译是基于操作系统和硬件平台进行的,node-gyp构建生成的.node动态链接库不能跨平台,所以通常我们在使用Node.js扩展时以依赖包的形式引入项目,当执行npm install时,自动调用node-gyp生成当前环境可用的.node扩展包。
上述方式需要即时编译,无疑会拖慢npm install过程。于是就出现了node-pre-gyp预构建工具,直接从仓库下载当前环境可用的Node.js扩展包。
以Xprofiler为例,根据当前系统、硬件平台、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语言非常火爆,在Node.js开发领域也大有成为基础设施的趋势。比如,Node.js作者的新项目Deno就是用rust语言开发的;使用swc开发的编译工具替代Babel提升性能;rust支持编译成Webassembly,在前后台都能执行,具有很好的前景。
很多公司对rust语言十分重视,例如下图中的TOP公司已经成为rust基金会白金会员,用实际行动支持rust语言的发展。foundation.rust-lang.org/
类似c++项目使用napi开发Node.js扩展,社区出现了napi-rs项目来支持rust语言开发Node.js扩展。github.com/napi-rs/nap…
FFI(Foreign Function Interface)语言交互接口,用一种编程语言写的程序能调用另一种编程语言写的函数,基本上成熟的编程语言都支持。使得我们可以在Node.js中直接调用c/c++、go、rust等语言编译生成的动态链接库,示例如下: github.com/node-ffi/no…
例如libmylibrary.dll或libmylibrary.so动态链接库的代码,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相关知识,请访问:nodejs 教程!
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!