您好,欢迎访问一九零五行业门户网

如何进行Node.js扩展开发?前置知识分享

如何进行node扩展开发?下面本篇文章就来介绍一下开发node.js扩展的前置知识,带你入门node.js扩展开发,希望对大家有所帮助!
为什么要开发node.js扩展1.node.js不适合cpu密集型业务,开发扩展使用libuv线程池做异步计算
2.需要更高的执行性能,例如使用c++、rust等比javascript更高效的语言
3.已有c++库,直接封装成node.js扩展提供给javascript调用,避免重复开发
4.通过javascript无法实现的能力,开发扩展增强node.js能力
什么是node.js扩展node.js扩展是文件扩展名为.node的二进制文件,本质上是动态链接库,可以理解为改了名的.dll或.so文件,可以被require加载
node.js module官方文档 nodejs.cn/api/modules…
node.js扩展的三种形式扩展类型基本描述node.js版本变化时改代码node.js版本变化时重新编译
直接写c++ 直接引用v8、libuv等库进行开发 是 是
nan 使用nan(native abstraction for node.js)进行开发 否 是
n-api 使用node-addon-api进行开发 否(abi版本需一致) 否(abi版本需一致)
直接写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复制代码
从hellow world开始以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                }            ]        }    ]}
asyncwork扩展开发可以参考官网示例,在项目中的execute方法中添加自定义代码,不妨动手一式。github.com/nodejs/node…
node-gyp构建工具node-gyp是node.js扩展的构建工具,依赖python和visual studio build tools,基于google的gyp(generate your projects)工具,chromium、v8等项目也在使用gyp构建。还可以使用cmake.js等工具进行编译构建。
npm config set msvs_version 2022npm 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-pre-gyp预构建由于编译是基于操作系统和硬件平台进行的,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…
其他形式的扩展 napi-rsrust语言非常火爆,在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…
直接调用动态链接库 node-ffiffi(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 教程!
以上就是如何进行node.js扩展开发?前置知识分享的详细内容。
其它类似信息

推荐信息