当前位置: 首页 > 后端技术 > Node.js

如何开发Node.jsNativeAdd-on?

时间:2023-04-03 15:30:22 Node.js

简介:一起为Node.js的插件生态做贡献~作者|jimschlight)、KevinEady、MichaelDawson(@mhdawson1)、NicolaDelGobbo(@NickNaso)等人,首次发表在Node.jsMedium博客上。关于N-APIN-API为Node.js带来了一个ABI稳定的附加API,简化了构建和开发支持跨Node.js版本的附加组件的负担。目前N-API的C++包node-addon-api每周下载量超过250万次,所有Node.jsLTS(长期支持版本)都已经支持N-APIv3或更高版本,Node.js15.x已经开始支持最新的N-APIv7.所以我们认为现在是退后一步,看看当前的Node.js附加组件开发体验的好时机。当我们在2016年开始研究N-API时(第一个提议是在2016年12月12日提出的),我们知道这将是一项非常长期的努力。Node.js社区生态系统中已经有很多现有的包,所以这个迁移过程将需要相当长的时间。好消息是我们已经从最初的想法中走了很长一段路。各种Node.js协作者、N-API团队和模块包作者已经克服了许多困难。目前,N-API已成为编写Node.js附加组件的默认和推荐方式。随着N-API的发展,N-API不断增加新的API以满足Node.js模块包作者将库迁移到N-API的新需求。当然,这个过程也是按照我们预先计划好的N-API进行了设计,以保持稳定性和向前兼容性。我们也很高兴看到这些模块包作者的积极反馈,比如https://twitter.com/mafintosh...话不多说,让我们来看看新加入的N个吧-API这几年的特点。新特性越来越多的开发者使用N-API和node-addon-api来开发Node.jsadd-on,我们也在不断地为N-API和node-addon-apiAdd-on开发添加新的关键特性和改进经验。这些改进可以分为3个主要类别,我们将在下面进行描述。多线程和异步编程随着Node.js的使用在开发者社区中越来越突出,处理OS接口和异步事件的需求也越来越大。Node.js是JavaScript单线程模型的一种实现,一个Node.js环境将只有一个可以访问JavaScript值的主线程。因此,在主线程上执行CPU繁重的任务会导致JavaScript程序被阻塞,导致事件和回调在事件队列中堆积。为了提高程序跨线程数据完整性的开发体验,我们收集了很多真实的案例需求,在N-API和N-API的C++包node-addon-api中带来了多种机制来解决问题工作线程回调JavaScript线程。根据使用场景,可以分为:AsyncWorker,提供单向、一次性回调任务封装,可以将本次任务的最终执行结果或异常信息通知给JavaScript;AsyncProgressWorker,与AsyncWorker类似,提供单向、一次性的回调任务封装,但增加了一种机制,将进度信息异步传递给JavaScript;线程安全函数,提供从任意线程、任意数量的线程、任意时间点到Node.jsJavaScript线程的回调机制。多Node.js上下文支持Node.js最近最令人兴奋的特性之一是[worker_threads],它提供了一个完整的Node.jsJavaScript执行线程,用于独立于Node.js主JavaScript线程的并发执行。这也意味着Node.js的附加组件也可以在这些工作线程中随着这些工作线程的启动和销毁而加载和卸载多次。但是,由于同一个进程中的这些工作线程共享同一个内存空间,多个附加实例必须考虑同时存在多个工作线程的可能性。另外,每个Node.js进程只会加载一次这些附加的动态库,这意味着这些附加的线程不安全的全局属性(比如全局静态变量)可以同时被多个线程访问,即就是,不能再这么简单粗暴的存储了。同样,C++类的静态数据成员也是以线程不安全的方式存储的,所以这种方式也需要避免。另外对于add-on,Node.js不保证单线程只会执行一个worker,所以也应该避免thread-local。在N-APIv6中,我们为每个Node.js实例(主线程JavaScript实例、worker实例等)引入了附加组件的存储空间。这样插件就可以获得进程中单个Node.js实例的唯一存储空间。同时,我们也提供了一些辅助方法来帮助插件开始使用这个特性:NAPI_MODULE_INIT()宏会将插件标记为一个模块,可以在Node.js中多次加载和卸载同样的过程。napi_get_instance_data()和napi_set_instance_data()用于安全访问单个Node.js实例为add-on创建的全局唯一存储空间;node-addon-api还提供了Addon类,它包装了上面提到的方法,它以C++友好的方式将给附加组件的存储空间封装在不同的工作线程中。因此,add-on开发者可以通过Addon来存储和创建全局变量等add-on数据,Node.js会在当前线程使用这个add-on时负责创建这个空间。其他辅助功能除了上述重要功能外,我们还发现了很多在维护Node.js插件的过程中经常用到的类型方法和功能,包括:Date对象;大整数;从JavaScript对象中获取任意键(如Symbol等);将Add-on创建的ArrayBuffer的底层存储与ArrayBuffer分离;构建构建工作流是Node.js插件维护者和插件用户非常重要的一个环节,也是N-API团队关注的重点之一,如CMake.js、node-pre-gyp和prebuild.曾经有一段时间只能使用node-gyp构建Node.js附加组件。对于一些已经使用CMake的库,除了node-gyp依赖项之外,CMake.js是构建附加组件的一个有吸引力的选择。我们还发布了使用CMake构建插件的示例。有关如何将CMake.js与N-API附加组件一起使用的更多详细信息,请访问N-API资源。开发Node.js附加组件后的一个重要实际问题是,附加组件的C/C++代码必须在npminstall期间在本地编译和链接。该编译过程需要本地安装C/C++工具链才能正常使用。而这种依赖性通常会阻碍没有安装这些工具链的附加组件用户使用此附加组件。目前针对该问题的解决方案一般都是预先构建二进制包,然后在安装时直接下载这些预先构建的包。有许多工具可用于预构建二进制包。node-pre-gyp通常将构建的二进制包上传到AWSS3。Prebuild类似,但将包上传到GitHubRelease。prebuildify是另一种选择。prebuildify和上面的工具相比,优点是这些二进制包在安装npminstall的时候就已经存在于本地了,不需要再从第三方服务中重新下载。虽然安装的npm包可能比较大,但是实际上,整个安装过程会相对快一些,因为不需要再从AWS或者GitHub上重新下载。入门我们在GitHub上准备了很多node-addon-examples,让开发者快速了解在常见场景下如何使用N-API和node-addon-api开发Node.jsadd-on。这个仓库的根目录包含了很多文件夹,代表了不同的使用场景,比如从简单的HelloWorld插件到复杂的多线程插件。每个示例目录会包含3个子目录,分别代表传统的NAN、N-API、node-addon-api开发插件示例。我们可以通过运行以下命令立即开始使用HelloWorld示例中的node-addon-api:$gitclonehttps://github.com/nodejs/node-addon-examples.git$cdnode-addon-examples/1_hello_world/node-addon-api/$npmi$节点。另一个重要资源是N-API资源。本站包含了从入门到深入开发构建Node.js插件的众多信息和资料,例如入门所需的工具;从NAN到N-API的迁移指南;gyp、CMake等);多个Node.js上下文支持和线程安全。结语从Node.js诞生开始,Node.js就支持通过C/C++代码向JavaScript暴露更多的特性接口。随着时间的推移,我们也意识到在实施、维护和分发这些附加组件方面存在很多困难。N-API被插件维护者认为是解决这些困难的一个非常核心的领域。因此整个N-API团队和社区开始为Node.js核心构建这样一个ABI稳定的附加API。代表N-API的CAPI现在是每个Node.js发行版的一部分,我们还有可以通过npm安装的node-addon-api来为这些CAPI提供C++包装器。N-API的诞生就是为了保证不同Node.js之间的ABI和API兼容性。切换Node.js大版本后需要重新编译附加模块;我们可以在Node.js以外的运行环境中使用V8作为JavaScript引擎来实现N-API,这也意味着这些为Node.js开发的插件可以兼容这些运行环境,比如BabylonNative,IoT。js和Electron,没有任何代码修改。N-API是一个纯CAPI,这意味着我们可以使用C/C++和运行时以外的语言来开发Node.js附加组件,例如Go或Rust。N-API从Node.jsv8.0.0开始作为实验功能发布。虽然广泛应用的过程比较缓慢,但模块开发者不断向我们提交反馈和贡献,这也有助于我们不断添加新功能。功能并开发新工具,以帮助开发人员构建更好的附加生态系统。如今,N-API广泛用于附加组件开发。例如,一些经常使用的附加模块已经迁移到基于N-API的开发:sharp(每周约90万次下载)bcrypt(每周约50万次下载)sqlite3(每周约30万次下载)在过去多年来,N-API得到了许多改进。对于插件开发者和用户来说,这也为他们带来了接近原生JavaScript模块的开发和使用体验。开始贡献我们一直在改进N-API和Node.js附加生态系统,但我们始终需要帮助。您可以通过以下方式帮助N-API在各种场景下做得更好:将您的附加组件迁移到N-API;帮助您的应用程序依赖附加组件迁移到N-API;为N-API提出建议,实现新特性;为node-addon-api提出并实施基于N-API的新功能;修复问题并增加node-addon-api的测试用例;修复问题并增加节点插件示例的测试用例;原文链接本文为阿里云原创内容,未经许可不得转载。