Node.js扩展的概念及形式是什么,如何实现
Admin 2022-10-29 群英技术资讯 279 次浏览
为什么要开发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 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-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-rs
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…
直接调用动态链接库 node-ffi
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); }
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
这篇文章主要介绍了事件冒泡、事件捕获和事件委托,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
本篇文章给大家带来了关于JavaScript的相关知识,其中主要整理了数据处理的相关问题,包括了数据的增删改查、数据的排序去重等等内容,下面一起来看一下,希望对大家有帮助。
前端编写测试用例时,在测试界面上的一些效果时,通常都希望能够模拟一些用户操作,而模拟用户操作最主要的方式就是用代码触发指定事件。通常一些元素上会自带一些触发事件的方法
这篇文章主要为大家详细介绍了jquery实现呼吸轮播效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
目录前言hover 的实现click 的实现矩形的坐标哪来的点在多边形内的其他判断方法穿透本章小结前言上个章节中我们已经给物体加上了被选中的效果,现在可以上点交互了,这个章节主要实现的就是物体的 hover 和 click 事件,当鼠标 hover 到物体上时,我们会改变鼠标的样式使其变成移动的样子;当 hover 到
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008