关于node.js:如何开发-Nodejs-Native-Addon

7次阅读

共计 4925 个字符,预计需要花费 13 分钟才能阅读完成。

简介:来一起为 Node.js 的 add-on 生态做奉献吧~
作者 | 吴成忠(昭朗)

这篇文章是由 Chengzhong Wu (@legendecas),Gabriel Schulhof (@gabrielschulhof),Jim Schlight (@jimschlight),Kevin Eady,Michael Dawson (@mhdawson1),Nicola Del Gobbo (@NickNaso) 等人编写的,首发在 Node.js Medium 博客。

对于 N -API

N-API 为 Node.js 带来了一个 ABI 稳固的 add-on API,简化了构建和开发反对跨 Node.js 版本的 add-on 的累赘。

目前 N-API 的 C++ 封装 node-addon-api 每周的下载量曾经超过了 250 万次,并且所有 Node.js LTS(长期反对版本)都曾经反对了 N-API v3 或者更高版本,Node.js 15.x 更曾经开始反对最新的 N-API v7。所以咱们认为这是一个十分好的工夫点来回头看一看目前 Node.js add-on 的开发体验。

当咱们在 2016 年开始投入 N-API 的工作(最开始的提案是在 2016 年 12 月 12 日提出的),咱们就晓得这会是一个十分长期的工作。Node.js 社区生态中曾经有十分多现存的包,所以这个迁徙过程将会继续相当长的一段时间。

不过好消息是,从最后的想法,到当初这段途程咱们曾经走过了十分长的道路。许许多多的艰难曾经由多位 Node.js Collaborator、N-API 团队和模块包作者们攻克。目前,N-API 曾经成为了默认、举荐的编写 Node.js add-on 的形式。

随着 N-API 的倒退,一直有新的 API 退出到 N-API 中去来满足 Node.js 模块包作者将他们的库向 N-API 迁徙中提出新需要,当然这个过程也依照咱们事后的设计 N-API 始终放弃着稳固、向前兼容性。

咱们也非常高兴地看到这些模块包作者们的踊跃反馈,比方 https://twitter.com/mafintosh…

不多说,咱们先来看看过来几年被增加到 N-API 中的新个性吧。

新个性

越来越多的开发者们开始应用 N-API 与 node-addon-api 开发 Node.js add-on,咱们也一直地为 N-API 和 node-addon-api 增加新的要害个性和改良 add-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 异步传递进度信息的机制;
  • Thread-safe functions,提供了从任意线程、任意数量的线程、任意工夫点向 Node.js JavaScript 线程回调的机制。

多 Node.js 上下文反对

Node.js 近期最让人兴奋的个性之一就是 [worker_threads],它提供了一个残缺的、然而独立于 Node.js 主 JavaScript 线程的并发执行的 Node.js JavaScript 执行线程。这也意味着 Node.js 的 add-on 也同样能够在这些 worker 线程中随着这些 worker 的启动与销毁被屡次加载、卸载。

不过因为这些同一个过程中的 worker 线程是共享了同一个内存空间的,多个 add-on 的实例必须思考到多个 worker 线程的同时存在的可能性。另外,每一个 Node.js 过程只会加载了一次这些 add-on 的动静库,这意味着这些 add-on 线程不平安的全局属性(比方全局动态变量)能够被多个线程同时拜访,也就不能再这么简略粗犷地存储了。

相似的,C++ 类的静态数据成员也是通过线程不平安的形式存储的,所以这个形式也须要被防止。另外,其实对于 add-on 来说,Node.js 也不保障单个线程只会用来执行一个 worker,所以 thread-local 也应该被防止。

在 N-API v6 中,咱们为每一个 Node.js 实例(主线程 JavaScript 实例、worker 实例等)都引入了一个用来给 add-on 应用的存储空间。这样,add-on 在一个过程中就能够取得对于单个 Node.js 实例惟一的存储空间了。同时咱们也提供了一些辅助办法来帮忙 add-on 开始应用这个个性:

  • NAPI_MODULE_INIT() 宏,会将 add-on 标记为能够被 Node.js 在同一个过程中能够屡次加载、卸载的模块。
  • napi_get_instance_data() 和 napi_set_instance_data() 用来平安地拜访单个 Node.js 实例给 add-on 创立的全局惟一存储空间;
  • node-addon-api 还提供了 Addon<T> 类,这个类包装了下面说所的办法,以 C++ 敌对的形式封装了这个给予 add-on 能够在不同的 worker 线程中应用的存储空间。因而,add-on 开发者能够将 add-on 的数据比方全局变量通过 Addon<T> 来存储并创立,而 Node.js 则会负责在以后线程应用这个 add-on 的时候创立这片空间。

其余辅助函数

除了以上几个重要性能之外,咱们也发现了许多在保护 Node.js add-on 的过程中常常会应用到的类型办法与函数,包含:

  • Date 对象;
  • BigInts;
  • 从 JavaScript 对象上获取任意键(如 Symbol 等);
  • 将 Add-on 创立的 ArrayBuffer 底层存储从 ArrayBuffer 上脱离;

构建

构建工作流对于 Node.js add-on 维护者与 add-on 使用者来说是十分重要的一个环节,也是 N -API 团队其中一个工作重心,比方 CMake.js, node-pre-gyp 和 prebuild。

已经 Node.js add-on 只能应用 node-gyp 来构建。对于一些曾经在应用 CMake 的库来说,CMake.js 就是除了 node-gyp 依赖用来构建 add-on 的一个十分吸引人的选项。咱们也曾经公布了一个应用 CMake 构建 add-on 的例子。

其余对于如何将 CMake.js 与 N-API add-on 一起应用的详细信息能够在 N-API Resource 获取到。

开发 Node.js add-on 之后一个重要的事实问题就是在 npm install 时,add-on 的 C/C++ 代码必须在本地编译、链接。这个编译过程须要本地装置有一个能够失常应用的 C/C++ 工具链。而这个依赖通常会成为没有装置这些工具链的 add-on 用户应用这个 add-on 的一个妨碍。现行的计划对于这个问题个别都是事后构建二进制包,而后在装置时间接下载这些事后构建的包。

有许多工具能够用来事后构建二进制包。node-pre-gyp 通常会将构建进去的二进制包上传到 AWS S3。prebuild 也相似,不过是将包上传到 GitHub Release。

prebuildify 则是另外一个可选项。而 prebuildify 相比于上述的工具来说,长处在于在 npm install 装置好时,本地就曾经有这些二进制包了,而不须要再次从第三方服务上下载。尽管装置的 npm 包可能会更大,不过在理论实际中因为不须要再次从 AWS 或者 GitHub 上下载,整个装置过程会绝对更加疾速。

开始上手

咱们曾经在 GitHub 上筹备了十分多的 node-addon-examples 来给开发者疾速理解常见场景该如何应用 N-API 和 node-addon-api 来开发 Node.js add-on。这个仓库的根目录蕴含了许多的文件夹,这些文件夹就代表了不同的应用场景,比方从简略的 Hello World add-on,到简单的多线程 add-on。每一个样例目录会蕴含 3 个子目录,别离代表了传统的 NAN,N-API,和 node-addon-api 开发 add-on 的例子。咱们能够间接运行上面的命令,立即从 Hello World 的例子开始应用 node-addon-api:

$ git clone https://github.com/nodejs/node-addon-examples.git
$ cd node-addon-examples/1_hello_world/node-addon-api/
$ npm i
$ node .

另一个重要的资源就是 N-API Resource。这个网站蕴含了开发、构建 Node.js add-on 的从入门到深刻的许多信息与材料,比方

  • 上手所需的工具;
  • 从 NAN 向 N-API 的迁徙导引;
  • 不同构建零碎的比照(node-gyp,CMake 等等);
  • 多 Node.js 上下文反对和线程平安。

结语

从 Node.js 诞生之初,Node.js 就反对通过 C/C++ 代码来给 JavaScript 裸露更多的个性接口。随着工夫积攒,咱们也意识到实现、保护、散发这些 add-on 始终存在许许多多的难点。而 N-API 就被 add-on 维护者们认为是解决这些难点的一个十分外围的畛域。所以整个 N -API 团队和社区都开始为 Node.js 外围建设起这样一套 ABI 稳固的 add-on API。

而代表了 N-API 的这些 C API 当初曾经是每一个 Node.js 公布版本的一部分,并且咱们也有了能够通过 npm 装置的 node-addon-api 来提供这些 C API 的 C++ 封装。N-API 在诞生之初,就是以在不同 Node.js 版本之间,甚至是 Major 版本之间保障 ABI 与 API 兼容性为指标,而这也曾经能够证实可能提供更多额定的益处:

  • 咱们不再须要在切换 Node.js 大版本之后从新编译 add-on 模块;
  • 咱们能够在除了应用 V8 作为 JavaScript 引擎的 Node.js 之外的运行环境实现 N-API,也意味着这些为 Node.js 开发的 add-on 无需批改任何代码即可兼容这些运行环境,比方 Babylon Native,IoT.js 和 Electron。
  • N-API 是单纯的 C API,这意味着咱们能够应用 C/C++ 之外的语言、运行时开发 Node.js add-on,比方 Go 或者是 Rust。

N-API 从 Node.js v8.0.0 开始以试验性功能公布到当初,尽管广泛应用的过程比拟迟缓,然而模块开发者们也一直地给咱们提交反馈与奉献,这也帮忙咱们一直地减少新个性和开发新的工具来帮忙开发者们构建一个更好的 add-on 生态。

明天,N-API 在 add-on 的开发中应用曾经十分宽泛。比方一些应用十分多的 add-on 模块都曾经迁徙至基于 N-API 开发:

  • sharp (每周 ~900k 下载量)
  • bcrypt (每周 ~500k 下载量)
  • sqlite3 (每周 ~300k 下载量)

在过来的几年中,N-API 取得了十分多的改良。而对于 add-on 开发者与用户来说,这也给他们带来了靠近于原生 JavaScript 模块的开发、应用体验。

开始奉献

咱们在继续一直地改良 N-API 和 Node.js 的 add-on 生态,然而咱们也始终十分须要帮忙。你能够在以下路径在多种场景帮忙 N-API 做的更好:

  • 将你的 add-on 迁徙到 N-API;
  • 帮忙你的利用依赖的 add-on 迁徙到 N-API;
  • 为 N-API 提出、实现新的个性;
  • 为 node-addon-api 提出、实现新的基于 N-API 的个性;
  • 为 node-addon-api 修复问题、减少测试用例;
  • 为 node-addon-examples 修复问题、减少测试用例;

原文链接
本文为阿里云原创内容,未经容许不得转载。

正文完
 0