Node.js v20.2.0 文档


目录

Node-API#

稳定性: 2 - 稳定

Node-API(以前称为 N-API)是用于构建原生插件的 API。 它独立于底层 JavaScript 运行时(例如 V8),并作为 Node.js 本身的一部分进行维护。 此 API 将在 Node.js 的各个版本中保持稳定的应用程序二进制接口 (ABI)。 它旨在将插件与底层 JavaScript 引擎的变化隔离开来,并允许为一个主要版本编译的模块无需重新编译即可在以后的 Node.js 主要版本上运行。 ABI 稳定性 指南提供了更深入的解释。

插件是使用标头为 C++ 插件 的部分中概述的相同方法/工具构建/打包的。 唯一的区别是原生代码使用的 API 集。 不使用 V8 或 Node.js 的原生抽象 API,而是使用 Node-API 中可用的函数。

Node-API 公开的 API 通常用于创建和操作 JavaScript 值。 概念和操作通常映射到 ECMA-262 语言规范中指定的想法。 API 具有以下属性:

  • 所有 Node-API 调用都会返回 napi_status 类型的状态代码。 此状态指示 API 调用是成功还是失败。
  • API 的返回值通过 out 参数传递。
  • 所有 JavaScript 值都被抽象为一个名为 napi_value 的不透明类型。
  • 如果出现错误状态代码,可以使用 napi_get_last_error_info 获取附加信息。 可以在错误处理部分 错误处理 中找到更多信息。

Node-API 是一种 C API,可确保跨 Node.js 版本和不同编译器级别的 ABI 稳定性。 C++ API 可以更容易使用。 为了支持使用 C++,该项目维护了一个名为 node-addon-api 的 C++ 封装器模块。 这个封装器提供了一个可内联的 C++ API。 使用 node-addon-api 构建的二进制文件将取决于 Node.js 导出的基于 Node-API C 的函数的符号。 node-addon-api 是编写调用 Node-API 的代码的更有效方式。 举个例子,下面的 node-addon-api 代码。 第一部分显示 node-addon-api 代码,第二部分显示插件中实际使用的内容。

Object obj = Object::New(env);
obj["foo"] = String::New(env, "bar"); 
napi_status status;
napi_value object, string;
status = napi_create_object(env, &object);
if (status != napi_ok) {
  napi_throw_error(env, ...);
  return;
}

status = napi_create_string_utf8(env, "bar", NAPI_AUTO_LENGTH, &string);
if (status != napi_ok) {
  napi_throw_error(env, ...);
  return;
}

status = napi_set_named_property(env, object, "foo", string);
if (status != napi_ok) {
  napi_throw_error(env, ...);
  return;
} 

最终结果是该插件仅使用导出的 C API。 因此,它仍然可以获得 C API 提供的 ABI 稳定性的好处。

当使用 node-addon-api 而不是 C API 时,从 node-addon-api 的 API 文档 开始。

Node-API 资源 为刚开始使用 Node-API 和 node-addon-api 的开发人员提供了很好的指导和技巧。 可以在 Node-API 媒体 页面上找到其他媒体资源。

ABI 稳定性的影响#

尽管 Node-API 提供了 ABI 稳定性保证,但 Node.js 的其他部分却没有,插件中使用的任何外部库也可能没有。 特别是,以下 API 均未提供跨主要版本的 ABI 稳定性保证:

  • 可通过任何方式获得的 Node.js C++ API

    #include <node.h>
    #include <node_buffer.h>
    #include <node_version.h>
    #include <node_object_wrap.h> 
  • libuv API,它也包含在 Node.js 中,可通过

    #include <uv.h> 
  • V8 API 可通过

    #include <v8.h> 

因此,为了使插件在 Node.js 主要版本之间保持 ABI 兼容,它必须通过限制自己使用来独占使用 Node-API

#include <node_api.h> 

并通过检查它使用的所有外部库,外部库使 ABI 稳定性保证类似于 Node-API。

构建#

与用 JavaScript 编写的模块不同,使用 Node-API 开发和部署 Node.js 原生插件需要一组额外的工具。 除了为 Node.js 开发所需的基本工具外,原生插件开发人员还需要一个可以将 C 和 C++ 代码编译为二进制文件的工具链。 此外,根据原生插件的部署方式,原生插件的用户还需要安装 C/C++ 工具链。

对于 Linux 开发人员,必要的 C/C++ 工具链包很容易获得。 GCC 在 Node.js 社区中被广泛用于跨各种平台构建和测试。 对于许多开发人员来说,LLVM 编译器基础设施也是一个不错的选择。

对于 Mac 开发人员,Xcode 提供了所有必需的编译器工具。 但是,没有必要安装整个 Xcode IDE。 以下命令安装必要的工具链:

xcode-select --install 

对于 Windows 开发人员,Visual Studio 提供了所有必需的编译器工具。 但是,没有必要安装整个 Visual Studio IDE。 以下命令安装必要的工具链:

npm install --global windows-build-tools 

以下部分描述了可用于开发和部署 Node.js 原生插件的其他工具。

构建工具#

此处列出的两种工具都要求原生插件的用户安装 C/C++ 工具链才能成功安装原生插件。

node-gyp#

node-gyp 是一个构建系统,基于 Google 的 GYP 工具的 gyp-next 分支,并与 npm 捆绑在一起。 GYP,因此 node-gyp,需要安装 Python。

从历史上看,node-gyp 一直是构建原生插件的首选工具。 它具有广泛的采用和文档。 但是,一些开发人员在 node-gyp 中遇到了限制。

CMake.js#

CMake.js 是基于 CMake 的替代构建系统。

对于已经使用 CMake 的项目或受 node-gyp 限制影响的开发人员,CMake.js 是一个不错的选择。

上传预编译的二进制文件#

此处列出的三个工具允许本地插件开发人员和维护人员创建二进制文件并将其上传到公共或私有服务器。 这些工具通常与 Travis CIAppVeyor 等 CI/CD 构建系统集成,为各种平台和架构构建和上传二进制文件。 这些二进制文件可供不需要安装 C/C++ 工具链的用户下载。

node-pre-gyp#

node-pre-gyp 是一个基于 node-gyp 的工具,它增加了将二进制文件上传到开发人员选择的服务器的能力。 node-pre-gyp 对将二进制文件上传到 Amazon S3 有特别好的支持。

prebuild#

prebuild 是一个支持使用 node-gyp 或 CMake.js 构建的工具。 与支持多种服务器的 node-pre-gyp 不同,prebuild 仅将二进制文件上传到 GitHub 发布。 prebuild 是使用 CMake.js 的 GitHub 项目的不错选择。

prebuildify#

prebuildify是一个基于node-gyp的工具。 prebuildify 的优点是构建的二进制文件在上传到 npm 时与原生插件捆绑在一起。 二进制文件从 npm 下载,并在安装原生插件时立即可供模块用户使用。

使用方法#

为了使用 Node-API 函数,在节点开发树中包含位于 src 目录中的文件 node_api.h

#include <node_api.h> 

这将为给定的 Node.js 版本选择默认的 NAPI_VERSION。 为了确保与特定版本的 Node-API 兼容,可以在包含标头时明确指定版本:

#define NAPI_VERSION 3
#include <node_api.h> 

这将 Node-API 表面限制为仅在指定(和更早)版本中可用的功能。

一些 Node-API 表面是实验性的,需要明确选择加入:

#define NAPI_EXPERIMENTAL
#include <node_api.h> 

在这种情况下,整个 API 表面,包括任何实验性 API,都将可用于模块代码。

Node-API 版本矩阵#

Node-API 版本是附加的,并且独立于 Node.js 进行版本控制。 版本 4 是版本 3 的扩展,因为它具有版本 3 的所有 API,并增加了一些内容。 这意味着无需为列为支持更高版本的 Node.js 的新版本重新编译。

1 2 3
v6.x v6.14.2*
v8.x v8.6.0** v8.10.0* v8.11.2
v9.x v9.0.0* v9.3.0* v9.11.0*
≥ v10.x 所有版本 所有版本 所有版本
4 5 6 7 8
v10.x v10.16.0 v10.17.0 v10.20.0 v10.23.0
v11.x v11.8.0
v12.x v12.0.0 v12.11.0 v12.17.0 v12.19.0 v12.22.0
v13.x v13.0.0 v13.0.0
v14.x v14.0.0 v14.0.0 v14.0.0 v14.12.0 v14.17.0
v15.x v15.0.0 v15.0.0 v15.0.0 v15.0.0 v15.12.0
v16.x v16.0.0 v16.0.0 v16.0.0 v16.0.0 v16.0.0

* Node-API 是实验性的。

** Node.js 8.0.0 包含 Node-API 作为实验。 它作为 Node-API 版本 1 发布,但继续发展直到 Node.js 8.6.0。 API 在 Node.js 8.6.0 之前的版本中有所不同。 我们推荐 Node-API 版本 3 或更高版本。

为 Node-API 记录的每个 API 都有一个名为 added in: 的标头,而稳定的 API 将有一个额外的标头 Node-API version:。 当使用支持 Node-API version: 或更高版本中所示的 Node-API 版本的 Node.js 版本时,API 可直接使用。 当使用不支持列出的 Node-API version: 的 Node.js 版本时,或者如果没有列出 Node-API version:,则只有在包含 node_api.hjs_native_api.h 之前包含 #define NAPI_EXPERIMENTAL 时,API 才可用。 如果某个 API 在晚于 added in: 中所示版本的 Node.js 版本上似乎不可用,那么这很可能是明显缺失的原因。

与从原生代码访问 ECMAScript 功能严格相关的 Node-API 可以在 js_native_api.hjs_native_api_types.h 中单独找到。 这些标头中定义的 API 包含在 node_api.hnode_api_types.h 中。 标头以这种方式构造,以便允许在 Node.js 之外实现 Node-API。 对于这些实现,Node.js 特定的 API 可能不适用。

插件的 Node.js 特定部分可以与将实际功能暴露给 JavaScript 环境的代码分开,以便后者可以与 Node-API 的多个实现一起使用。 在下面的示例中,addon.caddon.h 仅引用 js_native_api.h。 这确保了 addon.c 可以被重用以针对 Node-API 的 Node.js 实现或 Node.js 之外的任何 Node-API 实现进行编译。

addon_node.c 是一个单独的文件,其中包含插件的 Node.js 特定入口点,并在插件加载到 Node.js 环境时通过调用 addon.c 来实例化插件。

// addon.h
#ifndef _ADDON_H_
#define _ADDON_H_
#include <js_native_api.h>
napi_value create_addon(napi_env env);
#endif  // _ADDON_H_ 
// addon.c
#include "addon.h"

#define NAPI_CALL(env, call)                                      \
  do {                                                            \
    napi_status status = (call);                                  \
    if (status != napi_ok) {                                      \
      const napi_extended_error_info* error_info = NULL;          \
      napi_get_last_error_info((env), &error_info);               \
      const char* err_message = error_info->error_message;        \
      bool is_pending;                                            \
      napi_is_exception_pending((env), &is_pending);              \
      if (!is_pending) {                                          \
        const char* message = (err_message == NULL)               \
            ? "empty error message"                               \
            : err_message;                                        \
        napi_throw_error((env), NULL, message);                   \
        return NULL;                                              \
      }                                                           \
    }                                                             \
  } while(0)

static napi_value
DoSomethingUseful(napi_env env, napi_callback_info info) {
  // Do something useful.
  return NULL;
}

napi_value create_addon(napi_env env) {
  napi_value result;
  NAPI_CALL(env, napi_create_object(env, &result));

  napi_value exported_function;
  NAPI_CALL(env, napi_create_function(env,
                                      "doSomethingUseful",
                                      NAPI_AUTO_LENGTH,
                                      DoSomethingUseful,
                                      NULL,
                                      &exported_function));

  NAPI_CALL(env, napi_set_named_property(env,
                                         result,
                                         "doSomethingUseful",
                                         exported_function));

  return result;
} 
// addon_node.c
#include <node_api.h>
#include "addon.h"

NAPI_MODULE_INIT() {
  // This function body is expected to return a `napi_value`.
  // The variables `napi_env env` and `napi_value exports` may be used within
  // the body, as they are provided by the definition of `NAPI_MODULE_INIT()`.
  return create_addon(env);
} 

环境生命周期 API#

ECMAScript 语言规范第 8.7 节 将 "代理" 的概念定义为运行 JavaScript 代码的独立环境。 进程可以同时或按顺序启动和终止多个此类代理。

一个 Node.js 环境对应一个 ECMAScript Agent。 在主进程中,启动时创建一个环境,可以在单独的线程上创建额外的环境作为工作线程。 当Node.js嵌入到另一个应用程序中时,应用程序的主线程也可能在应用程序的生命周期中多次构造和销毁Node.js环境,使得应用程序创建的每个Node.js环境可能,在 反过来,在其生命周期中创建和销毁额外的环境作为工作线程。

从原生插件的角度来看,这意味着它提供的绑定可以从多个上下文中多次调用,甚至可以同时从多个线程中调用。

原生插件可能需要分配它们在 Node.js 环境的生命周期中使用的全局状态,以便该状态对于插件的每个实例都是唯一的。

为此,Node-API 提供了一种关联数据的方法,使其生命周期与 Node.js 环境的生命周期相关联。

napi_set_instance_data#

napi_status napi_set_instance_data(napi_env env,
                                   void* data,
                                   napi_finalize finalize_cb,
                                   void* finalize_hint); 
  • [in] env: 调用 Node-API 调用的环境。
  • [in] data: 可用于此实例的绑定的数据项。
  • [in] finalize_cb: 拆除环境时调用的函数。 该函数接收 data 以便释放它。 napi_finalize 提供了更多详细信息。
  • [in] finalize_hint: 在收集期间传递给最终回调的可选提示。

如果 API 成功,则返回 napi_ok

此 API 将 data 与当前运行的 Node.js 环境相关联。 稍后可以使用 napi_get_instance_data() 检索 data。 通过先前调用 napi_set_instance_data() 设置的与当前运行的 Node.js 环境关联的任何现有数据都将被覆盖。 如果之前调用提供了 finalize_cb,则不会调用它。

napi_get_instance_data#

napi_status napi_get_instance_data(napi_env env,
                                   void** data); 
  • [in] env: 调用 Node-API 调用的环境。
  • [out] data: 之前通过调用 napi_set_instance_data() 与当前运行的 Node.js 环境相关联的数据项。

如果 API 成功,则返回 napi_ok

此 API 检索以前通过 napi_set_instance_data() 与当前运行的 Node.js 环境关联的数据。 如果没有设置数据,则调用成功,data 将设置为 NULL

基本的 Node-API 数据类型#

Node-API 将以下基本数据类型公开为各种 API 使用的抽象。 这些 API 应该被视为不透明的,只能通过其他 Node-API 调用进行自省。

napi_status#

指示 Node-API 调用成功或失败的完整状态代码。 目前支持以下状态码。

typedef enum {
  napi_ok,
  napi_invalid_arg,
  napi_object_expected,
  napi_string_expected,
  napi_name_expected,
  napi_function_expected,
  napi_number_expected,
  napi_boolean_expected,
  napi_array_expected,
  napi_generic_failure,
  napi_pending_exception,
  napi_cancelled,
  napi_escape_called_twice,
  napi_handle_scope_mismatch,
  napi_callback_scope_mismatch,
  napi_queue_full,
  napi_closing,
  napi_bigint_expected,
  napi_date_expected,
  napi_arraybuffer_expected,
  napi_detachable_arraybuffer_expected,
  napi_would_deadlock,  /* unused */
  napi_no_external_buffers_allowed
} napi_status; 

如果 API 返回失败状态时需要额外的信息,可以通过调用 napi_get_last_error_info 获取。

napi_extended_error_info#

typedef struct {
  const char* error_message;
  void* engine_reserved;
  uint32_t engine_error_code;
  napi_status error_code;
} napi_extended_error_info; 
  • error_message: UTF8 编码的字符串,包含错误的 VM 中立描述。
  • engine_reserved: 为特定于 VM 的错误详细信息保留。 目前尚未为任何 VM 实现此功能。
  • engine_error_code: 特定于 VM 的错误代码。 目前尚未为任何 VM 实现此功能。
  • error_code: 源自最后一个错误的 Node-API 状态代码。

有关其他信息,请参阅 错误处理 部分。

napi_env#

napi_env 用于表示底层 Node-API 实现可用于持久化 VM 特定状态的上下文。 此结构在调用时传递给原生函数,并且在进行 Node-API 调用时必须传回。 具体来说,调用初始原生函数时传入的相同 napi_env 必须传递给任何后续的嵌套 Node-API 调用。 出于一般重用的目的缓存 napi_env,以及在不同 Worker 线程上运行的同一插件的实例之间传递 napi_env 是不允许的。 当卸载原生插件的实例时,napi_env 变得无效。 此事件的通知通过给 napi_add_env_cleanup_hooknapi_set_instance_data 的回调传递。

napi_value#

这是一个用于表示 JavaScript 值的不透明指针。

napi_threadsafe_function#

这是一个不透明的指针,表示可以通过 napi_call_threadsafe_function() 从多个线程异步调用的 JavaScript 函数。

napi_threadsafe_function_release_mode#

赋予 napi_release_threadsafe_function() 的值指示线程安全函数是立即关闭 (napi_tsfn_abort) 还是仅释放 (napi_tsfn_release) 并因此可通过 napi_acquire_threadsafe_function()napi_call_threadsafe_function() 进行后续使用。

typedef enum {
  napi_tsfn_release,
  napi_tsfn_abort
} napi_threadsafe_function_release_mode; 

napi_threadsafe_function_call_mode#

赋予 napi_call_threadsafe_function() 的值,以指示只要与线程安全函数关联的队列已满,调用是否应阻塞。

typedef enum {
  napi_tsfn_nonblocking,
  napi_tsfn_blocking
} napi_threadsafe_function_call_mode; 

Node-API 内存管理类型#

napi_handle_scope#

这是一种抽象,用于控制和修改在特定范围内创建的对象的生命周期。 通常,Node-API 值是在句柄范围的上下文中创建的。 当从 JavaScript 调用原生方法时,将存在默认句柄范围。 如果用户没有显式创建新的句柄范围,Node-API 值将在默认句柄范围内创建。 对于原生方法执行之外的任何代码调用(例如,在 libuv 回调调用期间),模块需要在调用任何可能导致创建 JavaScript 值的函数之前创建范围。

句柄作用域使用 napi_open_handle_scope 创建,使用 napi_close_handle_scope 销毁。 关闭作用域可以向 GC 表明在句柄作用域的生命周期内创建的所有 napi_value 不再从当前堆栈帧中引用。

有关详细信息,请查看 对象生命周期管理

napi_escapable_handle_scope#

可转义句柄范围是一种特殊类型的句柄范围,用于将在特定句柄范围内创建的值返回到父范围。

napi_ref#

这是用于引用 napi_value 的抽象。 这允许用户管理 JavaScript 值的生命周期,包括明确定义它们的最小生命周期。

有关详细信息,请查看 对象生命周期管理

napi_type_tag#

存储为两个无符号 64 位整数的 128 位值。 它作为一个 UUID,JavaScript 对象或 外部的 可以是 "tagged",以确保它们属于某种类型。 这是比 napi_instanceof 更强的检查,因为如果对象的原型被操纵,后者会报告误报。 类型标记与 napi_wrap 一起使用时最有用,因为它确保从封装对象中检索的指针可以安全地转换为与先前应用于 JavaScript 对象的类型标记相对应的原生类型。

typedef struct {
  uint64_t lower;
  uint64_t upper;
} napi_type_tag; 

napi_async_cleanup_hook_handle#

napi_add_async_cleanup_hook 返回的不透明值。 当异步清理事件链完成时,它必须传递给 napi_remove_async_cleanup_hook

Node-API 回调类型#

napi_callback_info#

传递给回调函数的不透明数据类型。 它可用于获取有关调用回调的上下文的附加信息。

napi_callback#

用户提供的原生函数的函数指针类型,这些函数将通过 Node-API 公开给 JavaScript。 回调函数应满足以下签名:

typedef napi_value (*napi_callback)(napi_env, napi_callback_info); 

除非出于 对象生命周期管理 中讨论的原因,否则无需在 napi_callback 中创建句柄和/或回调范围。

napi_finalize#

附加组件的函数指针类型提供的函数允许用户在外部拥有的数据准备好清理时收到通知,因为与其关联的对象已被垃圾收集。 用户必须提供满足以下签名的函数,该函数将在对象的集合上调用。 目前,napi_finalize 可用于查明何时收集具有外部数据的对象。

typedef void (*napi_finalize)(napi_env env,
                              void* finalize_data,
                              void* finalize_hint); 

除非出于 对象生命周期管理 中讨论的原因,否则无需在函数体内创建句柄和/或回调范围。

napi_async_execute_callback#

与支持异步操作的函数一起使用的函数指针。 回调函数必须满足以下签名:

typedef void (*napi_async_execute_callback)(napi_env env, void* data); 

此函数的实现必须避免进行执行 JavaScript 或与 JavaScript 对象交互的 Node-API 调用。 Node-API 调用应该在 napi_async_complete_callback 中。 不要使用 napi_env 参数,因为它可能会导致 JavaScript 的执行。

napi_async_complete_callback#

与支持异步操作的函数一起使用的函数指针。 回调函数必须满足以下签名:

typedef void (*napi_async_complete_callback)(napi_env env,
                                             napi_status status,
                                             void* data); 

除非出于 对象生命周期管理 中讨论的原因,否则无需在函数体内创建句柄和/或回调范围。

napi_threadsafe_function_call_js#

与异步线程安全函数调用一起使用的函数指针。 回调将在主线程上调用。 它的目的是使用从一个辅助线程通过队列到达的数据项来构造调用 JavaScript 所需的参数,通常是通过 napi_call_function,然后调用 JavaScript。

通过队列从辅助线程到达的数据在 data 参数中给出,要调用的 JavaScript 函数在 js_callback 参数中给出。

Node-API 在调用此回调之前设置环境,因此通过 napi_call_function 而不是通过 napi_make_callback 调用 JavaScript 函数就足够了。

回调函数必须满足以下签名:

typedef void (*napi_threadsafe_function_call_js)(napi_env env,
                                                 napi_value js_callback,
                                                 void* context,
                                                 void* data); 
  • [in] env: 用于 API 调用的环境,或者 NULL,如果线程安全函数正在被拆除并且 data 可能需要被释放。
  • [in] js_callback: 要调用的 JavaScript 函数,或者 NULL,如果线程安全函数正在被拆除并且 data 可能需要被释放。 如果线程安全函数是在没有 js_callback 的情况下创建的,它也可能是 NULL
  • [in] context: 用于创建线程安全函数的可选数据。
  • [in] data: 由辅助线程创建的数据。 回调负责将此原生数据转换为 JavaScript 值(使用 Node-API 函数),这些值可以在调用 js_callback 时作为参数传递。 这个指针完全由线程和这个回调管理。 因此这个回调应该释放数据。

除非出于 对象生命周期管理 中讨论的原因,否则无需在函数体内创建句柄和/或回调范围。

napi_cleanup_hook#

napi_add_env_cleanup_hook 一起使用的函数指针。 当环境被拆除时,它将被调用。

回调函数必须满足以下签名:

typedef void (*napi_cleanup_hook)(void* data); 

napi_async_cleanup_hook#

napi_add_async_cleanup_hook 一起使用的函数指针。 当环境被拆除时,它将被调用。

回调函数必须满足以下签名:

typedef void (*napi_async_cleanup_hook)(napi_async_cleanup_hook_handle handle,
                                        void* data); 

函数体应启动异步清理操作,在清理操作结束时必须在调用 napi_remove_async_cleanup_hook 时传递 handle

错误处理#

Node-API 使用返回值和 JavaScript 异常来处理错误。 以下部分解释了每种情况的方法。

返回值#

所有 Node-API 函数共享相同的错误处理模式。 所有 API 函数的返回类型都是 napi_status

如果请求成功并且没有抛出未捕获的 JavaScript 异常,则返回值将为 napi_ok。 如果发生错误并且抛出异常,则将返回错误的 napi_status 值。 如果抛出异常且未发生错误,则返回 napi_pending_exception

在返回 napi_oknapi_pending_exception 以外的返回值的情况下,必须调用 napi_is_exception_pending 来检查是否有异常挂起。 有关更多详细信息,请参阅异常部分。

napi_api_types.h 中定义了整套可能的 napi_status 值。

napi_status 返回值提供了所发生错误的独立于 VM 的表示。 在某些情况下,能够获得更详细的信息很有用,包括表示错误的字符串以及特定于 VM(引擎)的信息。

为了检索此信息,提供了 napi_get_last_error_info,它返回 napi_extended_error_info 结构。 napi_extended_error_info结构体的格式如下:

typedef struct napi_extended_error_info {
  const char* error_message;
  void* engine_reserved;
  uint32_t engine_error_code;
  napi_status error_code;
}; 
  • error_message: 所发生错误的文本表示。
  • engine_reserved: 不透明手柄仅供引擎使用。
  • engine_error_code: VM 特定的错误代码。
  • error_code: 最后一个错误的节点 API 状态代码。

napi_get_last_error_info 返回最后一次调用 Node-API 的信息。

不要依赖任何扩展信息的内容或格式,因为它不受 SemVer 的约束并且可能随时更改。 它仅用于记录目的。

napi_get_last_error_info#
napi_status
napi_get_last_error_info(napi_env env,
                         const napi_extended_error_info** result); 
  • [in] env: 调用 API 的环境。
  • [out] result: 包含有关错误的更多信息的 napi_extended_error_info 结构。

如果 API 成功,则返回 napi_ok

此 API 检索 napi_extended_error_info 结构,其中包含有关发生的最后一个错误的信息。

返回的 napi_extended_error_info 的内容仅在对同一 env 调用 Node-API 函数之前有效。 这包括对 napi_is_exception_pending 的调用,因此可能经常需要复制信息以便以后使用。 error_message 中返回的指针指向一个静态定义的字符串,因此如果您在调用另一个 Node-API 函数之前将它从 error_message 字段(将被覆盖)中复制出来,则可以安全地使用该指针。

不要依赖任何扩展信息的内容或格式,因为它不受 SemVer 的约束并且可能随时更改。 它仅用于记录目的。

即使存在挂起的 JavaScript 异常,也可以调用此 API。

异常#

任何 Node-API 函数调用都可能导致挂起的 JavaScript 异常。 任何 API 函数都是这种情况,即使是那些可能不会导致 JavaScript 执行的函数也是如此。

如果函数返回的 napi_statusnapi_ok,则没有异常挂起,也不需要额外的操作。 如果返回的 napi_status 不是 napi_oknapi_pending_exception,为了尝试恢复并继续而不是简单地立即返回,必须调用 napi_is_exception_pending 以确定异常是否挂起。

在许多情况下,当调用 Node-API 函数并且异常已经挂起时,该函数将立即返回 napi_statusnapi_pending_exception。 然而,并非所有功能都是如此。 Node-API 允许调用函数的子集,以便在返回 JavaScript 之前进行一些最小的清理。 在这种情况下,napi_status 将反映函数的状态。 它不会反映以前未决的异常。 为避免混淆,请在每次函数调用后检查错误状态。

当异常悬而未决时,可以采用两种方法之一。

第一种方法是进行任何适当的清理,然后返回,以便执行返回到 JavaScript。 作为转换回 JavaScript 的一部分,将在 JavaScript 代码中调用原生方法的位置抛出异常。 当异常挂起时,大多数 Node-API 调用的行为是未指定的,许多只会返回 napi_pending_exception,因此尽可能少地执行,然后返回到可以处理异常的 JavaScript。

第二种方法是尝试处理异常。 在某些情况下,原生代码可以捕获异常,采取适当的操作,然后继续。 仅在已知可以安全处理异常的特定情况下才建议这样做。 在这些情况下,napi_get_and_clear_last_exception 可用于获取和清除异常。 成功时,结果将包含最后抛出的 JavaScript Object 的句柄。 如果确定,在检索异常后,异常无法处理,毕竟可以用 napi_throw 重新抛出它,其中 error 是要抛出的 JavaScript 值。

如果原生代码需要抛出异常或确定 napi_value 是否是 JavaScript Error 对象的实例,还可以使用以下实用函数: napi_throw_errornapi_throw_type_errornapi_throw_range_errornode_api_throw_syntax_errornapi_is_error

如果原生代码需要创建 Error 对象,还可以使用以下实用函数: napi_create_errornapi_create_type_errornapi_create_range_errornode_api_create_syntax_error,其中结果是指代新创建的 JavaScript Error 对象的 napi_value

Node.js 项目正在为内部生成的所有错误添加错误代码。 目标是让应用程序使用这些错误代码进行所有错误检查。 关联的错误消息将保留,但仅用于记录和显示,期望消息可以在不应用 SemVer 的情况下更改。 为了使用 Node-API 支持此模型,无论是内部功能还是模块特定功能(作为其良好实践),throw_create_ 函数采用可选代码参数,该参数是要添加到错误中的代码字符串 目的。 如果可选参数是 NULL,则没有代码与错误关联。 如果提供了代码,则与错误关联的名称也会更新为:

originalName [code] 

其中 originalName 是与错误关联的原始名称,code 是提供的代码。 例如,如果代码是 'ERR_ERROR_1' 并且正在创建 TypeError,则名称将是:

TypeError [ERR_ERROR_1] 

napi_throw#
NAPI_EXTERN napi_status napi_throw(napi_env env, napi_value error); 
  • [in] env: 调用 API 的环境。
  • [in] error: 要抛出的 JavaScript 值。

如果 API 成功,则返回 napi_ok

此 API 抛出提供的 JavaScript 值。

napi_throw_error#
NAPI_EXTERN napi_status napi_throw_error(napi_env env,
                                         const char* code,
                                         const char* msg); 
  • [in] env: 调用 API 的环境。
  • [in] code: 要在错误上设置的可选错误代码。
  • [in] msg: 表示与错误关联的文本的 C 字符串。

如果 API 成功,则返回 napi_ok

此 API 会抛出带有所提供文本的 JavaScript Error

napi_throw_type_error#
NAPI_EXTERN napi_status napi_throw_type_error(napi_env env,
                                              const char* code,
                                              const char* msg); 
  • [in] env: 调用 API 的环境。
  • [in] code: 要在错误上设置的可选错误代码。
  • [in] msg: 表示与错误关联的文本的 C 字符串。

如果 API 成功,则返回 napi_ok

此 API 会抛出带有所提供文本的 JavaScript TypeError

napi_throw_range_error#
NAPI_EXTERN napi_status napi_throw_range_error(napi_env env,
                                               const char* code,
                                               const char* msg); 
  • [in] env: 调用 API 的环境。
  • [in] code: 要在错误上设置的可选错误代码。
  • [in] msg: 表示与错误关联的文本的 C 字符串。

如果 API 成功,则返回 napi_ok

此 API 会抛出带有所提供文本的 JavaScript RangeError

node_api_throw_syntax_error#

稳定性: 1 - 实验

NAPI_EXTERN napi_status node_api_throw_syntax_error(napi_env env,
                                                    const char* code,
                                                    const char* msg); 
  • [in] env: 调用 API 的环境。
  • [in] code: 要在错误上设置的可选错误代码。
  • [in] msg: 表示与错误关联的文本的 C 字符串。

如果 API 成功,则返回 napi_ok

此 API 会抛出带有所提供文本的 JavaScript SyntaxError

napi_is_error#
NAPI_EXTERN napi_status napi_is_error(napi_env env,
                                      napi_value value,
                                      bool* result); 
  • [in] env: 调用 API 的环境。
  • [in] value: 要检查的 napi_value
  • [out] result: 如果 napi_value 表示错误,则设置为 true 的布尔值,否则设置为 false。

如果 API 成功,则返回 napi_ok

此 API 查询 napi_value 以检查它是否表示错误对象。

napi_create_error#
NAPI_EXTERN napi_status napi_create_error(napi_env env,
                                          napi_value code,
                                          napi_value msg,
                                          napi_value* result); 
  • [in] env: 调用 API 的环境。
  • [in] code: 可选的 napi_value,带有与错误关联的错误代码的字符串。
  • [in] msg: napi_value 引用 JavaScript string 用作 Error 的消息。
  • [out] result: napi_value 表示创建的错误。

如果 API 成功,则返回 napi_ok

此 API 返回带有所提供文本的 JavaScript Error

napi_create_type_error#
NAPI_EXTERN napi_status napi_create_type_error(napi_env env,
                                               napi_value code,
                                               napi_value msg,
                                               napi_value* result); 
  • [in] env: 调用 API 的环境。
  • [in] code: 可选的 napi_value,带有与错误关联的错误代码的字符串。
  • [in] msg: napi_value 引用 JavaScript string 用作 Error 的消息。
  • [out] result: napi_value 表示创建的错误。

如果 API 成功,则返回 napi_ok

此 API 返回带有所提供文本的 JavaScript TypeError

napi_create_range_error#
NAPI_EXTERN napi_status napi_create_range_error(napi_env env,
                                                napi_value code,
                                                napi_value msg,
                                                napi_value* result); 
  • [in] env: 调用 API 的环境。
  • [in] code: 可选的 napi_value,带有与错误关联的错误代码的字符串。
  • [in] msg: napi_value 引用 JavaScript string 用作 Error 的消息。
  • [out] result: napi_value 表示创建的错误。

如果 API 成功,则返回 napi_ok

此 API 返回带有所提供文本的 JavaScript RangeError

node_api_create_syntax_error#

稳定性: 1 - 实验

NAPI_EXTERN napi_status node_api_create_syntax_error(napi_env env,
                                                     napi_value code,
                                                     napi_value msg,
                                                     napi_value* result); 
  • [in] env: 调用 API 的环境。
  • [in] code: 可选的 napi_value,带有与错误关联的错误代码的字符串。
  • [in] msg: napi_value 引用 JavaScript string 用作 Error 的消息。
  • [out] result: napi_value 表示创建的错误。

如果 API 成功,则返回 napi_ok

此 API 返回带有所提供文本的 JavaScript SyntaxError

napi_get_and_clear_last_exception#
napi_status napi_get_and_clear_last_exception(napi_env env,
                                              napi_value* result); 
  • [in] env: 调用 API 的环境。
  • [out] result: 如果一个未决则异常,否则为 NULL

如果 API 成功,则返回 napi_ok

即使存在挂起的 JavaScript 异常,也可以调用此 API。

napi_is_exception_pending#
napi_status napi_is_exception_pending(napi_env env, bool* result); 
  • [in] env: 调用 API 的环境。
  • [out] result: 如果异常挂起,则设置为 true 的布尔值。

如果 API 成功,则返回 napi_ok

即使存在挂起的 JavaScript 异常,也可以调用此 API。

napi_fatal_exception#
napi_status napi_fatal_exception(napi_env env, napi_value err); 
  • [in] env: 调用 API 的环境。
  • [in] err: 传递给 'uncaughtException' 的错误。

在 JavaScript 中触发 'uncaughtException'。 如果异步回调抛出无法恢复的异常,则很有用。

致命错误#

如果原生插件中出现不可恢复的错误,则可以抛出致命错误以立即终止进程。

napi_fatal_error#
NAPI_NO_RETURN void napi_fatal_error(const char* location,
                                     size_t location_len,
                                     const char* message,
                                     size_t message_len); 
  • [in] location: 发生错误的可选位置。
  • [in] location_len: 位置的长度(以字节为单位),如果它以 null 结尾则为 NAPI_AUTO_LENGTH
  • [in] message: 与错误关联的消息。
  • [in] message_len: 消息的长度(以字节为单位),如果以 null 结尾则为 NAPI_AUTO_LENGTH

函数调用不返回,进程将终止。

即使存在挂起的 JavaScript 异常,也可以调用此 API。

对象生命周期管理#

在进行 Node-API 调用时,底层 VM 的堆中对象的句柄可能会作为 napi_values 返回。 这些句柄必须持有对象 'live',直到原生代码不再需要它们,否则这些对象可能会在原生代码使用完它们之前被收集。

当返回对象句柄时,它们与“范围”相关联。 默认作用域的生命周期与本地方法调用的生命周期相关。 结果是,默认情况下,句柄保持有效,并且与这些句柄关联的对象将在原生方法调用的生命周期内保持活动状态。

然而,在许多情况下,句柄必须在比本地方法更短或更长的生命周期内保持有效。 以下部分描述了可用于更改默认句柄寿命的 Node-API 函数。

使句柄寿命短于本地方法#

通常需要使句柄的生命周期短于本地方法的生命周期。 例如,考虑一个本地方法,它有一个循环遍历大型数组中的元素:

for (int i = 0; i < 1000000; i++) {
  napi_value result;
  napi_status status = napi_get_element(env, object, i, &result);
  if (status != napi_ok) {
    break;
  }
  // do something with element
} 

这将导致创建大量句柄,消耗大量资源。 此外,即使原生代码只能使用最近的句柄,所有关联的对象也将保持活动状态,因为它们都共享相同的范围。

为了处理这种情况,Node-API 提供了建立新的 'scope' 的能力,新创建的句柄将与之关联。 一旦不再需要这些句柄,范围可以是 'closed',并且与该范围关联的任何句柄都将失效。 可用于打开/关闭范围的方法是 napi_open_handle_scopenapi_close_handle_scope

Node-API 仅支持单个嵌套的范围层次结构。 任何时候都只有一个活动范围,所有新句柄都将与该范围关联,同时它处于活动状态。 必须按照打开范围的相反顺序关闭范围。 此外,在从该方法返回之前,必须关闭在原生方法中创建的所有作用域。

以前面的例子为例,添加对 napi_open_handle_scopenapi_close_handle_scope 的调用将确保在整个循环执行过程中最多只有一个句柄有效:

for (int i = 0; i < 1000000; i++) {
  napi_handle_scope scope;
  napi_status status = napi_open_handle_scope(env, &scope);
  if (status != napi_ok) {
    break;
  }
  napi_value result;
  status = napi_get_element(env, object, i, &result);
  if (status != napi_ok) {
    break;
  }
  // do something with element
  status = napi_close_handle_scope(env, scope);
  if (status != napi_ok) {
    break;
  }
} 

嵌套作用域时,有时内部作用域的句柄需要超出该作用域的生命周期。 Node-API 支持 'escapable scope' 以支持这种情况。 可转义作用域允许一个句柄为 'promoted',以便 'escapes' 当前作用域和句柄的生命周期从当前作用域变为外部作用域。

可用于打开/关闭可转义范围的方法是 napi_open_escapable_handle_scopenapi_close_escapable_handle_scope

提升句柄的请求是通过 napi_escape_handle 触发的,只能调用一次。

napi_open_handle_scope#
NAPI_EXTERN napi_status napi_open_handle_scope(napi_env env,
                                               napi_handle_scope* result); 
  • [in] env: 调用 API 的环境。
  • [out] result: napi_value 代表新范围。

如果 API 成功,则返回 napi_ok

此 API 开辟了一个新的范围。

napi_close_handle_scope#
NAPI_EXTERN napi_status napi_close_handle_scope(napi_env env,
                                                napi_handle_scope scope); 
  • [in] env: 调用 API 的环境。
  • [in] scope: napi_value 表示要关闭的范围。

如果 API 成功,则返回 napi_ok

此 API 关闭传入的范围。 必须按照创建范围的相反顺序关闭范围。

即使存在挂起的 JavaScript 异常,也可以调用此 API。

napi_open_escapable_handle_scope#
NAPI_EXTERN napi_status
    napi_open_escapable_handle_scope(napi_env env,
                                     napi_handle_scope* result); 
  • [in] env: 调用 API 的环境。
  • [out] result: napi_value 代表新范围。

如果 API 成功,则返回 napi_ok

此 API 会打开一个新范围,从中可以将一个对象提升到外部范围。

napi_close_escapable_handle_scope#
NAPI_EXTERN napi_status
    napi_close_escapable_handle_scope(napi_env env,
                                      napi_handle_scope scope); 
  • [in] env: 调用 API 的环境。
  • [in] scope: napi_value 表示要关闭的范围。

如果 API 成功,则返回 napi_ok

此 API 关闭传入的范围。 必须按照创建范围的相反顺序关闭范围。

即使存在挂起的 JavaScript 异常,也可以调用此 API。

napi_escape_handle#
napi_status napi_escape_handle(napi_env env,
                               napi_escapable_handle_scope scope,
                               napi_value escapee,
                               napi_value* result); 
  • [in] env: 调用 API 的环境。
  • [in] scope: napi_value 代表当前范围。
  • [in] escapee: napi_value 表示要转义的 JavaScript Object
  • [out] result: napi_value 表示外部作用域中转义的 Object 的句柄。

如果 API 成功,则返回 napi_ok

此 API 提升 JavaScript 对象的句柄,使其在外部作用域的生命周期内有效。 每个作用域只能调用一次。 如果多次调用,将返回错误。

即使存在挂起的 JavaScript 异常,也可以调用此 API。

对生命周期比原生方法长的值的引用#

在某些情况下,插件需要能够创建和引用生命周期比单个本地方法调用更长的值。 例如,要创建构造函数并稍后在创建实例的请求中使用该构造函数,必须可以在许多不同的实例创建请求中引用构造函数对象。 这对于如前一节所述作为 napi_value 返回的普通句柄是不可能的。 普通句柄的生命周期由作用域管理,所有作用域都必须在本地方法结束之前关闭。

Node-API 提供了创建对值的持久引用的方法。 每个引用都有一个值为 0 或更高的关联计数,这决定了引用是否会使相应的值保持活动状态。 计数为 0 的引用不会阻止收集值。 对象(对象、函数、外部)和符号类型的值正在成为“弱”引用,并且在未被收集时仍然可以访问。 其他类型的值在计数变为 0 时被释放并且不能再从引用访问。 任何大于 0 的计数都将阻止收集值。

符号值有不同的风格。 只有使用 Symbol() 构造函数调用创建的局部符号才支持真正的弱引用行为。 使用 Symbol.for() 调用创建的全局注册符号始终保持强引用,因为垃圾收集器不收集它们。 Symbol.iterator 等知名符号也是如此。 它们也永远不会被垃圾收集器收集。 JavaScript 的 WeakRefWeakMap 类型在使用已注册符号时会返回错误,但它们会成功用于本地和众所周知的符号。

可以使用初始引用计数创建引用。 然后可以通过 napi_reference_refnapi_reference_unref 修改计数。 如果在引用计数为 0 时收集对象,则所有后续调用以获取与引用 napi_get_reference_value 关联的对象将为返回的 napi_value 返回 NULL。 尝试为其对象已收集的引用调用 napi_reference_ref 会导致错误。

Node-API 版本 8 及更早版本仅允许为一组有限的值类型创建引用,包括对象、外部、函数和符号。 但是,在较新的 Node-API 版本中,可以为任何值类型创建引用。

一旦插件不再需要引用,就必须删除它们。 删除引用后,将不再阻止收集相应的对象。 未能删除持久引用会导致 'memory leak' 永久保留用于持久引用的原生内存和堆上的相应对象。

可以创建多个指向同一个对象的持久引用,每个持久引用将根据其各自的计数使对象保持活动状态。 对同一对象的多个持久引用可能会导致原生内存意外保持活动状态。 持久引用的原生结构必须保持活动状态,直到执行引用对象的终结器。 如果为同一对象创建新的持久引用,则不会运行该对象的终结器,并且不会释放先前持久引用指向的原生内存。 这可以通过在可能的情况下除了 napi_reference_unref 之外还调用 napi_delete_reference 来避免。

napi_create_reference#
NAPI_EXTERN napi_status napi_create_reference(napi_env env,
                                              napi_value value,
                                              uint32_t initial_refcount,
                                              napi_ref* result); 
  • [in] env: 调用 API 的环境。
  • [in] value: 正在为其创建引用的 napi_value
  • [in] initial_refcount: 新引用的初始引用计数。
  • [out] result: napi_ref 指向新的引用。

如果 API 成功,则返回 napi_ok

该 API 对传入的值创建一个具有指定引用计数的新引用。

在 Node-API 版本 8 及更早版本中,只能为对象、函数、外部和符号值类型创建引用。 但是,在较新的 Node-API 版本中,可以为任何值类型创建引用。

napi_delete_reference#
NAPI_EXTERN napi_status napi_delete_reference(napi_env env, napi_ref ref); 
  • [in] env: 调用 API 的环境。
  • [in] ref: napi_ref 被删除。

如果 API 成功,则返回 napi_ok

该 API 删除传入的引用。

即使存在挂起的 JavaScript 异常,也可以调用此 API。

napi_reference_ref#
NAPI_EXTERN napi_status napi_reference_ref(napi_env env,
                                           napi_ref ref,
                                           uint32_t* result); 
  • [in] env: 调用 API 的环境。
  • [in] ref: napi_ref,其引用计数将增加。
  • [out] result: 新的引用计数。

如果 API 成功,则返回 napi_ok

此 API 增加传入引用的引用计数并返回生成的引用计数。

napi_reference_unref#
NAPI_EXTERN napi_status napi_reference_unref(napi_env env,
                                             napi_ref ref,
                                             uint32_t* result); 
  • [in] env: 调用 API 的环境。
  • [in] ref: 将减少其引用计数的 napi_ref
  • [out] result: 新的引用计数。

如果 API 成功,则返回 napi_ok

此 API 递减传入引用的引用计数并返回生成的引用计数。

napi_get_reference_value#
NAPI_EXTERN napi_status napi_get_reference_value(napi_env env,
                                                 napi_ref ref,
                                                 napi_value* result); 
  • [in] env: 调用 API 的环境。
  • [in] ref: 请求相应值的 napi_ref
  • [out] result: napi_ref 引用的 napi_value

如果 API 成功,则返回 napi_ok

如果仍然有效,此 API 将返回 napi_value,表示与 napi_ref 关联的 JavaScript 值。 否则,结果将为 NULL

当前 Node.js 环境退出时的清理#

虽然 Node.js 进程通常会在退出时释放其所有资源,但 Node.js 的嵌入程序或未来的 Worker 支持可能需要插件来注册清理钩子,一旦当前 Node.js 环境退出,这些钩子就会运行。

Node-API 提供了注册和取消注册此类回调的功能。 当这些回调运行时,插件持有的所有资源都应该被释放。

napi_add_env_cleanup_hook#
NODE_EXTERN napi_status napi_add_env_cleanup_hook(napi_env env,
                                                  napi_cleanup_hook fun,
                                                  void* arg); 

一旦当前 Node.js 环境退出,将 fun 注册为要使用 arg 参数运行的函数。

可以使用不同的 arg 值安全地多次指定一个函数。 在这种情况下,它也会被多次调用。 不允许多次提供相同的 funarg 值,否则会导致进程中止。

钩子将以相反的顺序调用,即最近添加的钩子将首先被调用。

可以使用 napi_remove_env_cleanup_hook 删除此钩子。 通常,当为其添加此钩子的资源无论如何都被拆除时,就会发生这种情况。

对于异步清理,napi_add_async_cleanup_hook 可用。

napi_remove_env_cleanup_hook#
NAPI_EXTERN napi_status napi_remove_env_cleanup_hook(napi_env env,
                                                     void (*fun)(void* arg),
                                                     void* arg); 

一旦当前 Node.js 环境退出,将 fun 注销为要使用 arg 参数运行的函数。 参数和函数值都需要完全匹配。

该函数必须最初已注册到 napi_add_env_cleanup_hook,否则进程将中止。

napi_add_async_cleanup_hook#
NAPI_EXTERN napi_status napi_add_async_cleanup_hook(
    napi_env env,
    napi_async_cleanup_hook hook,
    void* arg,
    napi_async_cleanup_hook_handle* remove_handle); 
  • [in] env: 调用 API 的环境。
  • [in] hook: 在环境拆卸时调用的函数指针。
  • [in] arg: 调用时传递给 hook 的指针。
  • [out] remove_handle: 引用异步清理钩子的可选句柄。

hook 注册为 napi_async_cleanup_hook 类型的函数,作为在当前 Node.js 环境退出后使用 remove_handlearg 参数运行的函数。

napi_add_env_cleanup_hook 不同的是,hook 允许是异步的。

否则,行为通常与 napi_add_env_cleanup_hook 的行为相匹配。

如果 remove_handle 不是 NULL,则将在其中存储一个不透明的值,该值稍后必须传递给 napi_remove_async_cleanup_hook,无论钩子是否已被调用。 通常,当为其添加此钩子的资源无论如何都被拆除时,就会发生这种情况。

napi_remove_async_cleanup_hook#
NAPI_EXTERN napi_status napi_remove_async_cleanup_hook(
    napi_async_cleanup_hook_handle remove_handle); 

注销对应于 remove_handle 的清除钩子。 这将阻止执行钩子,除非它已经开始执行。 这必须在从 napi_add_async_cleanup_hook 获得的任何 napi_async_cleanup_hook_handle 值上调用。

在 Node.js 环境退出时完成#

Node.js 环境可能会在任意时间尽快拆除,不允许 JavaScript 执行,就像 worker.terminate() 的请求一样。 当环境被拆除时,JavaScript 对象、线程安全函数和环境实例数据的已注册 napi_finalize 回调将立即独立调用。

napi_finalize 回调的调用安排在手动注册的清理钩子之后。 为了确保在环境关闭期间插件完成的正确顺序以避免 napi_finalize 回调中的释放后使用,插件应该向 napi_add_env_cleanup_hooknapi_add_async_cleanup_hook 注册一个清理钩子,以便以正确的顺序手动释放分配的资源。

模块注册#

Node-API 模块的注册方式与其他模块类似,只是不使用 NODE_MODULE 宏,而是使用以下内容:

NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) 

下一个区别是 Init 方法的签名。 对于 Node-API 模块,它如下所示:

napi_value Init(napi_env env, napi_value exports); 

Init 的返回值被视为模块的 exports 对象。 为方便起见,Init 方法通过 exports 参数传递一个空对象。 如果 Init 返回 NULL,则作为 exports 传递的参数由模块导出。 Node-API 模块无法修改 module 对象,但可以将任何内容指定为模块的 exports 属性。

将方法 hello 添加为函数,以便它可以作为插件提供的方法调用:

napi_value Init(napi_env env, napi_value exports) {
  napi_status status;
  napi_property_descriptor desc = {
    "hello",
    NULL,
    Method,
    NULL,
    NULL,
    NULL,
    napi_writable | napi_enumerable | napi_configurable,
    NULL
  };
  status = napi_define_properties(env, exports, 1, &desc);
  if (status != napi_ok) return NULL;
  return exports;
} 

要为插件设置 require() 返回的函数:

napi_value Init(napi_env env, napi_value exports) {
  napi_value method;
  napi_status status;
  status = napi_create_function(env, "exports", NAPI_AUTO_LENGTH, Method, NULL, &method);
  if (status != napi_ok) return NULL;
  return method;
} 

定义一个类以便创建新实例(通常与 对象封装 一起使用):

// NOTE: partial example, not all referenced code is included
napi_value Init(napi_env env, napi_value exports) {
  napi_status status;
  napi_property_descriptor properties[] = {
    { "value", NULL, NULL, GetValue, SetValue, NULL, napi_writable | napi_configurable, NULL },
    DECLARE_NAPI_METHOD("plusOne", PlusOne),
    DECLARE_NAPI_METHOD("multiply", Multiply),
  };

  napi_value cons;
  status =
      napi_define_class(env, "MyObject", New, NULL, 3, properties, &cons);
  if (status != napi_ok) return NULL;

  status = napi_create_reference(env, cons, 1, &constructor);
  if (status != napi_ok) return NULL;

  status = napi_set_named_property(env, exports, "MyObject", cons);
  if (status != napi_ok) return NULL;

  return exports;
} 

您还可以使用 NAPI_MODULE_INIT 宏,它充当 NAPI_MODULE 的简写并定义 Init 函数:

NAPI_MODULE_INIT() {
  napi_value answer;
  napi_status result;

  status = napi_create_int64(env, 42, &answer);
  if (status != napi_ok) return NULL;

  status = napi_set_named_property(env, exports, "answer", answer);
  if (status != napi_ok) return NULL;

  return exports;
} 

所有 Node-API 插件都是上下文感知的,这意味着它们可以被加载多次。 声明此类模块时有一些设计注意事项。 上下文感知的插件 上的文档提供了更多详细信息。

宏调用后,变量 envexports 将在函数体内可用。

有关设置对象属性的更多详细信息,请参阅 使用 JavaScript 属性 部分。

有关一般构建插件模块的更多详细信息,请参阅现有 API。

使用 JavaScript 值#

Node-API 公开了一组 API 来创建所有类型的 JavaScript 值。 其中一些类型记录在 ECMAScript 语言规范第 6 节 下。

从根本上说,这些 API 用于执行以下操作之一:

  1. 创建一个新的 JavaScript 对象
  2. 从原始 C 类型转换为 Node-API 值
  3. 从 Node-API 值转换为原始 C 类型
  4. 获取全局实例包括 undefinednull

Node-API 值由类型 napi_value 表示。 任何需要 JavaScript 值的 Node-API 调用都采用 napi_value。 在某些情况下,API 会预先检查 napi_value 的类型。 但是,为了获得更好的性能,调用者最好确保所讨论的 napi_value 是 API 期望的 JavaScript 类型。

枚举类型#

napi_key_collection_mode#
typedef enum {
  napi_key_include_prototypes,
  napi_key_own_only
} napi_key_collection_mode; 

描述 Keys/Properties 过滤器枚举:

napi_key_collection_mode 限制了收集属性的范围。

napi_key_own_only 将收集的属性仅限于给定的对象。 napi_key_include_prototypes 也将包含对象原型链的所有键。

napi_key_filter#
typedef enum {
  napi_key_all_properties = 0,
  napi_key_writable = 1,
  napi_key_enumerable = 1 << 1,
  napi_key_configurable = 1 << 2,
  napi_key_skip_strings = 1 << 3,
  napi_key_skip_symbols = 1 << 4
} napi_key_filter; 

属性过滤器位。 它们可以被 or' 构建一个复合过滤器。

napi_key_conversion#
typedef enum {
  napi_key_keep_numbers,
  napi_key_numbers_to_strings
} napi_key_conversion; 

napi_key_numbers_to_strings 会将整数索引转换为字符串。 napi_key_keep_numbers 将返回整数索引的数字。

napi_valuetype#
typedef enum {
  // ES6 types (corresponds to typeof)
  napi_undefined,
  napi_null,
  napi_boolean,
  napi_number,
  napi_string,
  napi_symbol,
  napi_object,
  napi_function,
  napi_external,
  napi_bigint,
} napi_valuetype; 

描述 napi_value 的类型。 这通常对应于 ECMAScript 语言规范的 第 6.1 节 中描述的类型。 除了该部分中的类型外,napi_valuetype 还可以用外部数据表示 FunctionObject

napi_external 类型的 JavaScript 值在 JavaScript 中显示为普通对象,因此不能在其上设置任何属性,也没有原型。

napi_typedarray_type#
typedef enum {
  napi_int8_array,
  napi_uint8_array,
  napi_uint8_clamped_array,
  napi_int16_array,
  napi_uint16_array,
  napi_int32_array,
  napi_uint32_array,
  napi_float32_array,
  napi_float64_array,
  napi_bigint64_array,
  napi_biguint64_array,
} napi_typedarray_type; 

这表示 TypedArray 的基础二进制标量数据类型。 此枚举的元素对应于 ECMAScript 语言规范第 22.2 节

对象创建函数#

napi_create_array#
napi_status napi_create_array(napi_env env, napi_value* result) 
  • [in] env: 调用 Node-API 调用的环境。
  • [out] result: 代表 JavaScript Arraynapi_value

如果 API 成功,则返回 napi_ok

此 API 返回对应于 JavaScript Array 类型的 Node-API 值。 JavaScript 数组在 ECMAScript 语言规范的 第 22.1 节 中进行了描述。

napi_create_array_with_length#
napi_status napi_create_array_with_length(napi_env env,
                                          size_t length,
                                          napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [in] length: Array 的初始长度。
  • [out] result: 代表 JavaScript Arraynapi_value

如果 API 成功,则返回 napi_ok

此 API 返回对应于 JavaScript Array 类型的 Node-API 值。 Array 的长度属性设置为传入的长度参数。 但是,不保证底层缓冲区在创建数组时由 VM 预先分配。 该行为留给底层 VM 实现。 如果缓冲区必须是可以通过 C 直接读取和/或写入的连续内存块,请考虑使用 napi_create_external_arraybuffer

JavaScript 数组在 ECMAScript 语言规范的 第 22.1 节 中进行了描述。

napi_create_arraybuffer#
napi_status napi_create_arraybuffer(napi_env env,
                                    size_t byte_length,
                                    void** data,
                                    napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [in] length: 要创建的数组缓冲区的字节长度。
  • [out] data: 指向 ArrayBuffer 的底层字节缓冲区的指针。 data 可以选择性地通过传递 NULL 来忽略。
  • [out] result: 代表 JavaScript ArrayBuffernapi_value

如果 API 成功,则返回 napi_ok

此 API 返回对应于 JavaScript ArrayBuffer 的 Node-API 值。 ArrayBuffer 用于表示固定长度的二进制数据缓冲区。 它们通常用作 TypedArray 对象的后备缓冲区。 分配的 ArrayBuffer 将有一个底层字节缓冲区,其大小由传入的 length 参数决定。 如果调用者想要直接操作缓冲区,则可以选择将底层缓冲区返回给调用者。 此缓冲区只能直接从原生代码写入。 要从 JavaScript 写入此缓冲区,需要创建类型化数组或 DataView 对象。

JavaScript ArrayBuffer 对象在 ECMAScript 语言规范的 第 24.1 节 中进行了描述。

napi_create_buffer#
napi_status napi_create_buffer(napi_env env,
                               size_t size,
                               void** data,
                               napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [in] size: 底层缓冲区的大小(以字节为单位)。
  • [out] data: 指向底层缓冲区的原始指针。 data 可以选择性地通过传递 NULL 来忽略。
  • [out] result: 一个 napi_value 代表一个 node::Buffer

如果 API 成功,则返回 napi_ok

此 API 分配一个 node::Buffer 对象。 虽然这仍然是一个完全受支持的数据结构,但在大多数情况下使用 TypedArray 就足够了。

napi_create_buffer_copy#
napi_status napi_create_buffer_copy(napi_env env,
                                    size_t length,
                                    const void* data,
                                    void** result_data,
                                    napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [in] size: 输入缓冲区的大小(以字节为单位)(应与新缓冲区的大小相同)。
  • [in] data: 指向要从中复制的基础缓冲区的原始指针。
  • [out] result_data: 指向新 Buffer 的基础数据缓冲区的指针。 result_data 可以选择性地通过传递 NULL 来忽略。
  • [out] result: 一个 napi_value 代表一个 node::Buffer

如果 API 成功,则返回 napi_ok

此 API 分配一个 node::Buffer 对象并使用从传入缓冲区复制的数据对其进行初始化。 虽然这仍然是一个完全受支持的数据结构,但在大多数情况下使用 TypedArray 就足够了。

napi_create_date#
napi_status napi_create_date(napi_env env,
                             double time,
                             napi_value* result); 
  • [in] env: 调用 API 的环境。
  • [in] time: 自 1970 年 1 月 1 日 UTC 以来的 ECMAScript 时间值(以毫秒为单位)。
  • [out] result: 代表 JavaScript Datenapi_value

如果 API 成功,则返回 napi_ok

此 API 不遵守闰秒; 它们被忽略,因为 ECMAScript 符合 POSIX 时间规范。

此 API 分配一个 JavaScript Date 对象。

JavaScript Date 对象在 ECMAScript 语言规范的 第 20.3 节 中进行了描述。

napi_create_external#
napi_status napi_create_external(napi_env env,
                                 void* data,
                                 napi_finalize finalize_cb,
                                 void* finalize_hint,
                                 napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [in] data: 指向外部数据的原始指针。
  • [in] finalize_cb: 收集外部值时调用的可选回调。 napi_finalize 提供了更多详细信息。
  • [in] finalize_hint: 在收集期间传递给最终回调的可选提示。
  • [out] result: 表示外部值的 napi_value

如果 API 成功,则返回 napi_ok

此 API 分配一个附加有外部数据的 JavaScript 值。 这用于通过 JavaScript 代码传递外部数据,因此稍后可以使用 napi_get_value_external 由原生代码检索。

API 添加了一个 napi_finalize 回调,当刚刚创建的 JavaScript 对象被垃圾回收时将调用该回调。

创建的值不是对象,因此不支持附加属性。 它被认为是一个独特的值类型: 使用外部值调用 napi_typeof() 会产生 napi_external

napi_create_external_arraybuffer#
napi_status
napi_create_external_arraybuffer(napi_env env,
                                 void* external_data,
                                 size_t byte_length,
                                 napi_finalize finalize_cb,
                                 void* finalize_hint,
                                 napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [in] external_data: 指向 ArrayBuffer 的底层字节缓冲区的指针。
  • [in] byte_length: 底层缓冲区的字节长度。
  • [in] finalize_cb: 收集 ArrayBuffer 时调用的可选回调。 napi_finalize 提供了更多详细信息。
  • [in] finalize_hint: 在收集期间传递给最终回调的可选提示。
  • [out] result: 代表 JavaScript ArrayBuffernapi_value

如果 API 成功,则返回 napi_ok

除 Node.js 之外的一些运行时已放弃对外部缓冲区的支持。 在 Node.js 以外的运行时,此方法可能会返回 napi_no_external_buffers_allowed 以指示不支持外部缓冲区。 如本期 electron/issues/35801 中所述,Electron 就是这样一种运行时。

为了保持与所有运行时的最广泛兼容性,您可以在包含节点 API 标头之前在您的插件中定义 NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED。 这样做将隐藏创建外部缓冲区的 2 个函数。 如果您不小心使用其中一种方法,这将确保发生编译错误。

此 API 返回对应于 JavaScript ArrayBuffer 的 Node-API 值。 ArrayBuffer 的底层字节缓冲区是外部分配和管理的。 调用者必须确保字节缓冲区在调用 finalize 回调之前保持有效。

API 添加了一个 napi_finalize 回调,当刚刚创建的 JavaScript 对象被垃圾回收时将调用该回调。

JavaScript ArrayBuffer 在 ECMAScript 语言规范的 第 24.1 节 中描述。

napi_create_external_buffer#
napi_status napi_create_external_buffer(napi_env env,
                                        size_t length,
                                        void* data,
                                        napi_finalize finalize_cb,
                                        void* finalize_hint,
                                        napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [in] length: 输入缓冲区的大小(以字节为单位)(应与新缓冲区的大小相同)。
  • [in] data: 指向底层缓冲区的原始指针以暴露给 JavaScript。
  • [in] finalize_cb: 收集 ArrayBuffer 时调用的可选回调。 napi_finalize 提供了更多详细信息。
  • [in] finalize_hint: 在收集期间传递给最终回调的可选提示。
  • [out] result: 一个 napi_value 代表一个 node::Buffer

如果 API 成功,则返回 napi_ok

除 Node.js 之外的一些运行时已放弃对外部缓冲区的支持。 在 Node.js 以外的运行时,此方法可能会返回 napi_no_external_buffers_allowed 以指示不支持外部缓冲区。 如本期 electron/issues/35801 中所述,Electron 就是这样一种运行时。

为了保持与所有运行时的最广泛兼容性,您可以在包含节点 API 标头之前在您的插件中定义 NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED。 这样做将隐藏创建外部缓冲区的 2 个函数。 如果您不小心使用其中一种方法,这将确保发生编译错误。

此 API 分配一个 node::Buffer 对象并使用传入缓冲区支持的数据对其进行初始化。 虽然这仍然是一个完全受支持的数据结构,但在大多数情况下使用 TypedArray 就足够了。

API 添加了一个 napi_finalize 回调,当刚刚创建的 JavaScript 对象被垃圾回收时将调用该回调。

For Node.js >=4 BuffersUint8Array

napi_create_object#
napi_status napi_create_object(napi_env env, napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [out] result: 代表 JavaScript Objectnapi_value

如果 API 成功,则返回 napi_ok

此 API 分配默认的 JavaScript Object。 它相当于在 JavaScript 中执行 new Object()

JavaScript Object 类型在 ECMAScript 语言规范的 第 6.1.7 节 中进行了描述。

napi_create_symbol#
napi_status napi_create_symbol(napi_env env,
                               napi_value description,
                               napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [in] description: 可选的 napi_value,它指的是要设置为符号描述的 JavaScript string
  • [out] result: 代表 JavaScript symbolnapi_value

如果 API 成功,则返回 napi_ok

此 API 从 UTF8 编码的 C 字符串创建 JavaScript symbol 值。

JavaScript symbol 类型在 ECMAScript 语言规范的 第 19.4 节 中进行了描述。

node_api_symbol_for#

稳定性: 1 - 实验

napi_status node_api_symbol_for(napi_env env,
                                const char* utf8description,
                                size_t length,
                                napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [in] utf8description: UTF-8 C 字符串,表示用作符号描述的文本。
  • [in] length: 描述字符串的长度(以字节为单位),如果它以 null 结尾则为 NAPI_AUTO_LENGTH
  • [out] result: 代表 JavaScript symbolnapi_value

如果 API 成功,则返回 napi_ok

此 API 在全局注册表中搜索具有给定描述的现有符号。 如果该符号已经存在,它将被返回,否则将在注册表中创建一个新符号。

JavaScript symbol 类型在 ECMAScript 语言规范的 第 19.4 节 中进行了描述。

napi_create_typedarray#
napi_status napi_create_typedarray(napi_env env,
                                   napi_typedarray_type type,
                                   size_t length,
                                   napi_value arraybuffer,
                                   size_t byte_offset,
                                   napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [in] type: TypedArray 中元素的标量数据类型。
  • [in] length: TypedArray 中的元素数。
  • [in] arraybuffer: ArrayBuffer 是类型化数组的基础。
  • [in] byte_offset: ArrayBuffer 中开始投影 TypedArray 的字节偏移量。
  • [out] result: 代表 JavaScript TypedArraynapi_value

如果 API 成功,则返回 napi_ok

此 API 在现有的 ArrayBuffer 上创建一个 JavaScript TypedArray 对象。 TypedArray 对象在底层数据缓冲区上提供类似数组的视图,其中每个元素都具有相同的底层二进制标量数据类型。

It's required that (length * size_of_element) + byte_offset should be <= 传入的数组的字节大小。 如果不是,则引发 RangeError 异常。

JavaScript TypedArray 对象在 ECMAScript 语言规范的 第 22.2 节 中进行了描述。

napi_create_dataview#
napi_status napi_create_dataview(napi_env env,
                                 size_t byte_length,
                                 napi_value arraybuffer,
                                 size_t byte_offset,
                                 napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [in] length: DataView 中的元素数。
  • [in] arraybuffer: ArrayBufferDataView 的基础。
  • [in] byte_offset: ArrayBuffer 中开始投影 DataView 的字节偏移量。
  • [out] result: 代表 JavaScript DataViewnapi_value

如果 API 成功,则返回 napi_ok

此 API 在现有的 ArrayBuffer 上创建一个 JavaScript DataView 对象。 DataView 对象在底层数据缓冲区上提供类似数组的视图,但在 ArrayBuffer 中允许不同大小和类型的项目。

要求 byte_length + byte_offset 小于或等于传入数组的字节大小。 如果不是,则引发 RangeError 异常。

JavaScript DataView 对象在 ECMAScript 语言规范的 第 24.3 节 中进行了描述。

从 C 类型转换为 Node-API 的函数#

napi_create_int32#
napi_status napi_create_int32(napi_env env, int32_t value, napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: 要在 JavaScript 中表示的整数值。
  • [out] result: 代表 JavaScript numbernapi_value

如果 API 成功,则返回 napi_ok

该API用于将C int32_t类型转换为JavaScript number类型。

JavaScript number 类型在 ECMAScript 语言规范的 第 6.1.6 节 中进行了描述。

napi_create_uint32#
napi_status napi_create_uint32(napi_env env, uint32_t value, napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: 要在 JavaScript 中表示的无符号整数值。
  • [out] result: 代表 JavaScript numbernapi_value

如果 API 成功,则返回 napi_ok

该API用于将C uint32_t类型转换为JavaScript number类型。

JavaScript number 类型在 ECMAScript 语言规范的 第 6.1.6 节 中进行了描述。

napi_create_int64#
napi_status napi_create_int64(napi_env env, int64_t value, napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: 要在 JavaScript 中表示的整数值。
  • [out] result: 代表 JavaScript numbernapi_value

如果 API 成功,则返回 napi_ok

该API用于将C int64_t类型转换为JavaScript number类型。

JavaScript number 类型在 ECMAScript 语言规范的 第 6.1.6 节 中进行了描述。 请注意,无法在 JavaScript 中完全精确地表示 int64_t 的完整范围。 Number.MIN_SAFE_INTEGER -(2**53 - 1) - Number.MAX_SAFE_INTEGER (2**53 - 1) 范围之外的整数值将失去精度。

napi_create_double#
napi_status napi_create_double(napi_env env, double value, napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: 要在 JavaScript 中表示的双精度值。
  • [out] result: 代表 JavaScript numbernapi_value

如果 API 成功,则返回 napi_ok

该API用于将C double类型转换为JavaScript number类型。

JavaScript number 类型在 ECMAScript 语言规范的 第 6.1.6 节 中进行了描述。

napi_create_bigint_int64#
napi_status napi_create_bigint_int64(napi_env env,
                                     int64_t value,
                                     napi_value* result); 
  • [in] env: 调用 API 的环境。
  • [in] value: 要在 JavaScript 中表示的整数值。
  • [out] result: 代表 JavaScript BigIntnapi_value

如果 API 成功,则返回 napi_ok

此 API 将 C int64_t 类型转换为 JavaScript BigInt 类型。

napi_create_bigint_uint64#
napi_status napi_create_bigint_uint64(napi_env env,
                                      uint64_t value,
                                      napi_value* result); 
  • [in] env: 调用 API 的环境。
  • [in] value: 要在 JavaScript 中表示的无符号整数值。
  • [out] result: 代表 JavaScript BigIntnapi_value

如果 API 成功,则返回 napi_ok

此 API 将 C uint64_t 类型转换为 JavaScript BigInt 类型。

napi_create_bigint_words#
napi_status napi_create_bigint_words(napi_env env,
                                     int sign_bit,
                                     size_t word_count,
                                     const uint64_t* words,
                                     napi_value* result); 
  • [in] env: 调用 API 的环境。
  • [in] sign_bit: 确定生成的 BigInt 是正数还是负数。
  • [in] word_count: words 数组的长度。
  • [in] words: uint64_t little-endian 64 位字数组。
  • [out] result: 代表 JavaScript BigIntnapi_value

如果 API 成功,则返回 napi_ok

此 API 将一组无符号 64 位字转换为单个 BigInt 值。

生成的 BigInt 计算如下: (–1)sign_bit (words[0] × (2<s向上>64</晚饭>)0 + words[1] × (2<s向上>64</晚饭>)1 + …)

napi_create_string_latin1#
napi_status napi_create_string_latin1(napi_env env,
                                      const char* str,
                                      size_t length,
                                      napi_value* result); 
  • [in] env: 调用 API 的环境。
  • [in] str: 表示 ISO-8859-1 编码字符串的字符缓冲区。
  • [in] length: 字符串的长度(以字节为单位),如果它以 null 结尾则为 NAPI_AUTO_LENGTH
  • [out] result: 代表 JavaScript stringnapi_value

如果 API 成功,则返回 napi_ok

此 API 从 ISO-8859-1 编码的 C 字符串创建一个 JavaScript string 值。 复制原生字符串。

JavaScript string 类型在 ECMAScript 语言规范的 第 6.1.4 节 中进行了描述。

napi_create_string_utf16#
napi_status napi_create_string_utf16(napi_env env,
                                     const char16_t* str,
                                     size_t length,
                                     napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [in] str: 表示 UTF16-LE 编码字符串的字符缓冲区。
  • [in] length: 以两字节代码单元表示的字符串长度,如果它以 null 终止,则为 NAPI_AUTO_LENGTH
  • [out] result: 代表 JavaScript stringnapi_value

如果 API 成功,则返回 napi_ok

此 API 从 UTF16-LE 编码的 C 字符串创建 JavaScript string 值。 复制原生字符串。

JavaScript string 类型在 ECMAScript 语言规范的 第 6.1.4 节 中进行了描述。

napi_create_string_utf8#
napi_status napi_create_string_utf8(napi_env env,
                                    const char* str,
                                    size_t length,
                                    napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [in] str: 表示 UTF8 编码字符串的字符缓冲区。
  • [in] length: 字符串的长度(以字节为单位),如果它以 null 结尾则为 NAPI_AUTO_LENGTH
  • [out] result: 代表 JavaScript stringnapi_value

如果 API 成功,则返回 napi_ok

此 API 从 UTF8 编码的 C 字符串创建 JavaScript string 值。 复制原生字符串。

JavaScript string 类型在 ECMAScript 语言规范的 第 6.1.4 节 中进行了描述。

从 Node-API 转换为 C 类型的函数#

napi_get_array_length#
napi_status napi_get_array_length(napi_env env,
                                  napi_value value,
                                  uint32_t* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: napi_value 代表查询长度的 JavaScript Array
  • [out] result: uint32 代表数组的长度。

如果 API 成功,则返回 napi_ok

此 API 返回数组的长度。

Array 长度在 ECMAScript 语言规范的 第 22.1.4.1 节 中描述。

napi_get_arraybuffer_info#
napi_status napi_get_arraybuffer_info(napi_env env,
                                      napi_value arraybuffer,
                                      void** data,
                                      size_t* byte_length) 
  • [in] env: 调用 API 的环境。
  • [in] arraybuffer: napi_value代表被查询的ArrayBuffer
  • [out] data: ArrayBuffer 的底层数据缓冲区。 如果 byte_length 是 0,这可能是 NULL 或任何其他指针值。
  • [out] byte_length: 底层数据缓冲区的字节长度。

如果 API 成功,则返回 napi_ok

此 API 用于检索 ArrayBuffer 的底层数据缓冲区及其长度。

警告: 使用此 API 时要小心。 底层数据缓冲区的生命周期由 ArrayBuffer 管理,即使在返回后也是如此。 使用此 API 的一种可能的安全方法是与 napi_create_reference 结合使用,它可用于保证对 ArrayBuffer 生命周期的控制。 只要没有对可能触发 GC 的其他 API 的调用,在同一回调中使用返回的数据缓冲区也是安全的。

napi_get_buffer_info#
napi_status napi_get_buffer_info(napi_env env,
                                 napi_value value,
                                 void** data,
                                 size_t* length) 
  • [in] env: 调用 API 的环境。
  • [in] value: napi_value代表被查询的node::Buffer
  • [out] data: node::Buffer 的底层数据缓冲区。 如果长度是 0,这可能是 NULL 或任何其他指针值。
  • [out] length: 底层数据缓冲区的字节长度。

如果 API 成功,则返回 napi_ok

此 API 用于检索 node::Buffer 的底层数据缓冲区及其长度。

警告: 使用此 API 时要小心,因为如果底层数据缓冲区由 VM 管理,则无法保证其生命周期。

napi_get_prototype#
napi_status napi_get_prototype(napi_env env,
                               napi_value object,
                               napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [in] object: napi_value 表示要返回其原型的 JavaScript Object。 这将返回 Object.getPrototypeOf 的等价物(与函数的 prototype 属性不同)。
  • [out] result: napi_value 表示给定对象的原型。

如果 API 成功,则返回 napi_ok

napi_get_typedarray_info#
napi_status napi_get_typedarray_info(napi_env env,
                                     napi_value typedarray,
                                     napi_typedarray_type* type,
                                     size_t* length,
                                     void** data,
                                     napi_value* arraybuffer,
                                     size_t* byte_offset) 
  • [in] env: 调用 API 的环境。
  • [in] typedarray: napi_value 表示要查询其属性的 TypedArray
  • [out] type: TypedArray 中元素的标量数据类型。
  • [out] length: TypedArray 中的元素数。
  • [out] data: TypedArray 底层的数据缓冲区由 byte_offset 值调整,使其指向 TypedArray 中的第一个元素。 如果数组的长度是 0,这可能是 NULL 或任何其他指针值。
  • [out] arraybuffer: TypedArray 下的 ArrayBuffer
  • [out] byte_offset: 数组的第一个元素所在的基础原生数组中的字节偏移量。 data 参数的值已经过调整,因此 data 指向数组中的第一个元素。 因此,原生数组的第一个字节将位于 data - byte_offset

如果 API 成功,则返回 napi_ok

此 API 返回类型化数组的各种属性。

如果不需要该属性,则任何输出参数都可以是 NULL

警告: 使用此 API 时要小心,因为底层数据缓冲区由 VM 管理。

napi_get_dataview_info#
napi_status napi_get_dataview_info(napi_env env,
                                   napi_value dataview,
                                   size_t* byte_length,
                                   void** data,
                                   napi_value* arraybuffer,
                                   size_t* byte_offset) 
  • [in] env: 调用 API 的环境。
  • [in] dataview: napi_value 表示要查询其属性的 DataView
  • [out] byte_length: DataView 中的字节数。
  • [out] data: DataView 下的数据缓冲区。 如果 byte_length 是 0,这可能是 NULL 或任何其他指针值。
  • [out] arraybuffer: ArrayBufferDataView 的基础。
  • [out] byte_offset: 开始投影 DataView 的数据缓冲区中的字节偏移量。

如果 API 成功,则返回 napi_ok

如果不需要该属性,则任何输出参数都可以是 NULL

此 API 返回 DataView 的各种属性。

napi_get_date_value#
napi_status napi_get_date_value(napi_env env,
                                napi_value value,
                                double* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: napi_value 代表一个 JavaScript Date
  • [out] result: 作为 double 的时间值表示为自 1970 年 1 月 1 日 UTC 午夜以来的毫秒数。

此 API 不遵守闰秒; 它们被忽略,因为 ECMAScript 符合 POSIX 时间规范。

如果 API 成功,则返回 napi_ok。 如果传入非日期 napi_value,则返回 napi_date_expected

此 API 返回给定 JavaScript Date 的时间值的 C 双精度原语。

napi_get_value_bool#
napi_status napi_get_value_bool(napi_env env, napi_value value, bool* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: napi_value 代表 JavaScript Boolean
  • [out] result: 给定 JavaScript Boolean 的 C 布尔原语等价物。

如果 API 成功,则返回 napi_ok。 如果传入非布尔值 napi_value,则返回 napi_boolean_expected

此 API 返回给定 JavaScript Boolean 的 C 布尔原语等价物。

napi_get_value_double#
napi_status napi_get_value_double(napi_env env,
                                  napi_value value,
                                  double* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: napi_value 代表 JavaScript number
  • [out] result: 给定的 JavaScript number 的 C 双基本等价物。

如果 API 成功,则返回 napi_ok。 如果传入非数字 napi_value,则返回 napi_number_expected

此 API 返回给定 JavaScript number 的 C 双精度原语等价物。

napi_get_value_bigint_int64#
napi_status napi_get_value_bigint_int64(napi_env env,
                                        napi_value value,
                                        int64_t* result,
                                        bool* lossless); 
  • [in] env: 调用API的环境
  • [in] value: napi_value 代表 JavaScript BigInt
  • [out] result: 给定的 JavaScript BigInt 的 C int64_t 原语等价物。
  • [out] lossless: 指示 BigInt 值是否已无损转换。

如果 API 成功,则返回 napi_ok。 如果传入非 BigInt,则返回 napi_bigint_expected

此 API 返回给定 JavaScript BigInt 的 C int64_t 原语等价物。 如果需要,它将截断该值,将 lossless 设置为 false

napi_get_value_bigint_uint64#
napi_status napi_get_value_bigint_uint64(napi_env env,
                                        napi_value value,
                                        uint64_t* result,
                                        bool* lossless); 
  • [in] env: 调用 API 的环境。
  • [in] value: napi_value 代表 JavaScript BigInt
  • [out] result: 给定的 JavaScript BigInt 的 C uint64_t 原语等价物。
  • [out] lossless: 指示 BigInt 值是否已无损转换。

如果 API 成功,则返回 napi_ok。 如果传入非 BigInt,则返回 napi_bigint_expected

此 API 返回给定 JavaScript BigInt 的 C uint64_t 原语等价物。 如果需要,它将截断该值,将 lossless 设置为 false

napi_get_value_bigint_words#
napi_status napi_get_value_bigint_words(napi_env env,
                                        napi_value value,
                                        int* sign_bit,
                                        size_t* word_count,
                                        uint64_t* words); 
  • [in] env: 调用 API 的环境。
  • [in] value: napi_value 代表 JavaScript BigInt
  • [out] sign_bit: 表示 JavaScript BigInt 是正数还是负数的整数。
  • [in/out] word_count: 必须初始化为 words 数组的长度。 返回时,它将被设置为存储此 BigInt 所需的实际字数。
  • [out] words: 指向预分配的 64 位字数组的指针。

如果 API 成功,则返回 napi_ok

此 API 将单个 BigInt 值转换为符号位、64 位小端数组和数组中的元素数。 sign_bitwords 可能都设置为 NULL,以便只得到 word_count

napi_get_value_external#
napi_status napi_get_value_external(napi_env env,
                                    napi_value value,
                                    void** result) 
  • [in] env: 调用 API 的环境。
  • [in] value: napi_value 代表 JavaScript 外部值。
  • [out] result: 指向由 JavaScript 外部值封装的数据的指针。

如果 API 成功,则返回 napi_ok。 如果传入非外部 napi_value,则返回 napi_invalid_arg

此 API 检索先前传递给 napi_create_external() 的外部数据指针。

napi_get_value_int32#
napi_status napi_get_value_int32(napi_env env,
                                 napi_value value,
                                 int32_t* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: napi_value 代表 JavaScript number
  • [out] result: 给定的 JavaScript number 的 C int32 原语等价物。

如果 API 成功,则返回 napi_ok。 如果在 napi_number_expected 中传递了非数字 napi_value

此 API 返回给定 JavaScript number 的 C int32 原语等价物。

如果该数字超出 32 位整数的范围,则结果将被截断为与底部 32 位等效的值。 如果该值 > 2,这可能导致一个大的正数变成一个负数31 - 1.

非有限数值(NaN+Infinity-Infinity)将结果设置为零。

napi_get_value_int64#
napi_status napi_get_value_int64(napi_env env,
                                 napi_value value,
                                 int64_t* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: napi_value 代表 JavaScript number
  • [out] result: 给定的 JavaScript number 的 C int64 原语等价物。

如果 API 成功,则返回 napi_ok。 如果传入非数字 napi_value,则返回 napi_number_expected

此 API 返回给定 JavaScript number 的 C int64 原语等价物。

number values outside the range of Number.MIN_SAFE_INTEGER -(2**53 - 1) - Number.MAX_SAFE_INTEGER (2**53 - 1) 将失去精度。

非有限数值(NaN+Infinity-Infinity)将结果设置为零。

napi_get_value_string_latin1#
napi_status napi_get_value_string_latin1(napi_env env,
                                         napi_value value,
                                         char* buf,
                                         size_t bufsize,
                                         size_t* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: napi_value 代表 JavaScript 字符串。
  • [in] buf: 写入 ISO-8859-1 编码字符串的缓冲区。 如果传入 NULL,则在 result 中返回以字节为单位的字符串长度,不包括空终止符。
  • [in] bufsize: 目标缓冲区的大小。 当此值不足时,返回的字符串将被截断并以 null 终止。
  • [out] result: 复制到缓冲区中的字节数,不包括空终止符。

如果 API 成功,则返回 napi_ok。 如果传入非 string napi_value,则返回 napi_string_expected

此 API 返回对应于传入值的 ISO-8859-1 编码字符串。

napi_get_value_string_utf8#
napi_status napi_get_value_string_utf8(napi_env env,
                                       napi_value value,
                                       char* buf,
                                       size_t bufsize,
                                       size_t* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: napi_value 代表 JavaScript 字符串。
  • [in] buf: 将 UTF8 编码的字符串写入的缓冲区。 如果传入 NULL,则在 result 中返回以字节为单位的字符串长度,不包括空终止符。
  • [in] bufsize: 目标缓冲区的大小。 当此值不足时,返回的字符串将被截断并以 null 终止。
  • [out] result: 复制到缓冲区中的字节数,不包括空终止符。

如果 API 成功,则返回 napi_ok。 如果传入非 string napi_value,则返回 napi_string_expected

此 API 返回对应于传入值的 UTF8 编码字符串。

napi_get_value_string_utf16#
napi_status napi_get_value_string_utf16(napi_env env,
                                        napi_value value,
                                        char16_t* buf,
                                        size_t bufsize,
                                        size_t* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: napi_value 代表 JavaScript 字符串。
  • [in] buf: 将 UTF16-LE 编码字符串写入的缓冲区。 如果传入 NULL,则返回字符串的 2 字节代码单元长度,不包括空终止符。
  • [in] bufsize: 目标缓冲区的大小。 当此值不足时,返回的字符串将被截断并以 null 终止。
  • [out] result: 复制到缓冲区中的 2 字节代码单元数,不包括空终止符。

如果 API 成功,则返回 napi_ok。 如果传入非 string napi_value,则返回 napi_string_expected

此 API 返回对应于传入值的 UTF16 编码字符串。

napi_get_value_uint32#
napi_status napi_get_value_uint32(napi_env env,
                                  napi_value value,
                                  uint32_t* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: napi_value 代表 JavaScript number
  • [out] result: 将给定的 napi_value 等效为 uint32_t 的 C 原语。

如果 API 成功,则返回 napi_ok。 如果传入非数字 napi_value,则返回 napi_number_expected

此 API 将给定 napi_value 的 C 原语等效项返回为 uint32_t

获取全局实例的函数#

napi_get_boolean#
napi_status napi_get_boolean(napi_env env, bool value, napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: 要检索的布尔值。
  • [out] result: napi_value 表示要检索的 JavaScript Boolean 单例。

如果 API 成功,则返回 napi_ok

此 API 用于返回用于表示给定布尔值的 JavaScript 单例对象。

napi_get_global#
napi_status napi_get_global(napi_env env, napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [out] result: napi_value 代表 JavaScript global 对象。

如果 API 成功,则返回 napi_ok

此 API 返回 global 对象。

napi_get_null#
napi_status napi_get_null(napi_env env, napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [out] result: napi_value 代表 JavaScript null 对象。

如果 API 成功,则返回 napi_ok

此 API 返回 null 对象。

napi_get_undefined#
napi_status napi_get_undefined(napi_env env, napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [out] result: napi_value 代表 JavaScript Undefined 值。

如果 API 成功,则返回 napi_ok

此 API 返回 Undefined 对象。

使用 JavaScript 值和抽象操作#

Node-API 公开了一组 API 来对 JavaScript 值执行一些抽象操作。 其中一些操作记录在 ECMAScript 语言规范第 7 节 下。

这些 API 支持执行以下操作之一:

  1. 将 JavaScript 值强制转换为特定的 JavaScript 类型(例如 numberstring)。
  2. 检查 JavaScript 值的类型。
  3. 检查两个 JavaScript 值之间的相等性。

napi_coerce_to_bool#

napi_status napi_coerce_to_bool(napi_env env,
                                napi_value value,
                                napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: 要强制转换的 JavaScript 值。
  • [out] result: napi_value 代表强制的 JavaScript Boolean

如果 API 成功,则返回 napi_ok

该 API 实现了 ECMAScript 语言规范的 第 7.1.2 节 中定义的抽象操作 ToBoolean()

napi_coerce_to_number#

napi_status napi_coerce_to_number(napi_env env,
                                  napi_value value,
                                  napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: 要强制转换的 JavaScript 值。
  • [out] result: napi_value 代表强制的 JavaScript number

如果 API 成功,则返回 napi_ok

该 API 实现了 ECMAScript 语言规范的 第 7.1.3 节 中定义的抽象操作 ToNumber()。 如果传入的值是对象,此函数可能会运行 JS 代码。

napi_coerce_to_object#

napi_status napi_coerce_to_object(napi_env env,
                                  napi_value value,
                                  napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: 要强制转换的 JavaScript 值。
  • [out] result: napi_value 代表强制的 JavaScript Object

如果 API 成功,则返回 napi_ok

该 API 实现了 ECMAScript 语言规范的 第 7.1.13 节 中定义的抽象操作 ToObject()

napi_coerce_to_string#

napi_status napi_coerce_to_string(napi_env env,
                                  napi_value value,
                                  napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: 要强制转换的 JavaScript 值。
  • [out] result: napi_value 代表强制的 JavaScript string

如果 API 成功,则返回 napi_ok

该 API 实现了 ECMAScript 语言规范的 第 7.1.13 节 中定义的抽象操作 ToString()。 如果传入的值是对象,此函数可能会运行 JS 代码。

napi_typeof#

napi_status napi_typeof(napi_env env, napi_value value, napi_valuetype* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: 要查询其类型的 JavaScript 值。
  • [out] result: JavaScript 值的类型。

如果 API 成功,则返回 napi_ok

  • 如果 value 的类型不是已知的 ECMAScript 类型并且 value 不是外部值,则为 napi_invalid_arg

此 API 表示类似于在 ECMAScript 语言规范的 第 12.5.5 节 中定义的对象上调用 typeof 运算符的行为。 但是,存在一些差异:

  1. 它支持检测外部值。
  2. 它将 null 检测为单独的类型,而 ECMAScript typeof 将检测 object

如果 value 的类型无效,则返回错误。

napi_instanceof#

napi_status napi_instanceof(napi_env env,
                            napi_value object,
                            napi_value constructor,
                            bool* result) 
  • [in] env: 调用 API 的环境。
  • [in] object: 要检查的 JavaScript 值。
  • [in] constructor: 要检查的构造函数的 JavaScript 函数对象。
  • [out] result: 如果 object instanceof constructor 为 true,则设置为 true 的布尔值。

如果 API 成功,则返回 napi_ok

此 API 代表在 ECMAScript 语言规范的 第 12.10.4 节 中定义的对象上调用 instanceof 运算符。

napi_is_array#

napi_status napi_is_array(napi_env env, napi_value value, bool* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: 要检查的 JavaScript 值。
  • [out] result: 给定对象是否为数组。

如果 API 成功,则返回 napi_ok

该 API 表示调用对象上的 IsArray 操作,如 ECMAScript 语言规范的 第 7.2.2 节 中所定义。

napi_is_arraybuffer#

napi_status napi_is_arraybuffer(napi_env env, napi_value value, bool* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: 要检查的 JavaScript 值。
  • [out] result: 给定对象是否为 ArrayBuffer

如果 API 成功,则返回 napi_ok

该 API 检查传入的 Object 是否为数组缓冲区。

napi_is_buffer#

napi_status napi_is_buffer(napi_env env, napi_value value, bool* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: 要检查的 JavaScript 值。
  • [out] result: 给定的 napi_value 是否表示 node::Buffer 对象。

如果 API 成功,则返回 napi_ok

该 API 检查传入的 Object 是否为缓冲区。

napi_is_date#

napi_status napi_is_date(napi_env env, napi_value value, bool* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: 要检查的 JavaScript 值。
  • [out] result: 给定的 napi_value 是否表示 JavaScript Date 对象。

如果 API 成功,则返回 napi_ok

该 API 检查传入的 Object 是否为日期。

napi_is_error#

napi_status napi_is_error(napi_env env, napi_value value, bool* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: 要检查的 JavaScript 值。
  • [out] result: 给定的 napi_value 是否表示 Error 对象。

如果 API 成功,则返回 napi_ok

该 API 检查传入的 Object 是否为 Error

napi_is_typedarray#

napi_status napi_is_typedarray(napi_env env, napi_value value, bool* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: 要检查的 JavaScript 值。
  • [out] result: 给定的 napi_value 是否代表 TypedArray

如果 API 成功,则返回 napi_ok

此 API 检查传入的 Object 是否为类型化数组。

napi_is_dataview#

napi_status napi_is_dataview(napi_env env, napi_value value, bool* result) 
  • [in] env: 调用 API 的环境。
  • [in] value: 要检查的 JavaScript 值。
  • [out] result: 给定的 napi_value 是否代表 DataView

如果 API 成功,则返回 napi_ok

该 API 检查传入的 Object 是否为 DataView

napi_strict_equals#

napi_status napi_strict_equals(napi_env env,
                               napi_value lhs,
                               napi_value rhs,
                               bool* result) 
  • [in] env: 调用 API 的环境。
  • [in] lhs: 要检查的 JavaScript 值。
  • [in] rhs: 要检查的 JavaScript 值。
  • [out] result: 两个 napi_value 对象是否相等。

如果 API 成功,则返回 napi_ok

此 API 表示调用 ECMAScript 语言规范的 第 7.2.14 节 中定义的严格相等算法。

napi_detach_arraybuffer#

napi_status napi_detach_arraybuffer(napi_env env,
                                    napi_value arraybuffer) 
  • [in] env: 调用 API 的环境。
  • [in] arraybuffer: 要分离的 JavaScript ArrayBuffer

如果 API 成功,则返回 napi_ok。 如果传入不可分离的 ArrayBuffer,则返回 napi_detachable_arraybuffer_expected

通常,ArrayBuffer 是不可拆卸的,如果它之前已经拆卸过。 引擎可能会对 ArrayBuffer 是否可拆卸施加附加条件。 例如,V8 要求 ArrayBuffer 是外部的,即用 napi_create_external_arraybuffer 创建的。

此 API 表示调用 ArrayBuffer 分离操作,如 ECMAScript 语言规范的 第 24.1.1.3 节 中所定义。

napi_is_detached_arraybuffer#

napi_status napi_is_detached_arraybuffer(napi_env env,
                                         napi_value arraybuffer,
                                         bool* result) 
  • [in] env: 调用 API 的环境。
  • [in] arraybuffer: 要检查的 JavaScript ArrayBuffer
  • [out] result: arraybuffer是否分离。

如果 API 成功,则返回 napi_ok

如果 ArrayBuffer 的内部数据是 null,则认为 ArrayBuffer 已分离。

此 API 表示调用 ArrayBuffer IsDetachedBuffer 操作,如 ECMAScript 语言规范的 第 24.1.1.2 节 中所定义。

使用 JavaScript 属性#

Node-API 公开了一组 API 来获取和设置 JavaScript 对象的属性。 其中一些类型记录在 ECMAScript 语言规范第 7 节 下。

JavaScript 中的属性表示为键和值的元组。 从根本上说,Node-API 中的所有属性键都可以用以下形式之一表示:

  • 命名: 一个简单的 UTF8 编码字符串
  • 整数索引: 由 uint32_t 表示的索引值
  • JavaScript 值: 这些在 Node-API 中由 napi_value 表示。 这可以是代表 stringnumbersymbolnapi_value

Node-API 值由类型 napi_value 表示。 任何需要 JavaScript 值的 Node-API 调用都采用 napi_value。 但是,调用者有责任确保所讨论的 napi_value 是 API 期望的 JavaScript 类型。

本节中记录的 API 提供了一个简单的接口来获取和设置 napi_value 表示的任意 JavaScript 对象的属性。

例如,考虑以下 JavaScript 代码片段:

const obj = {};
obj.myProp = 123; 

可以通过以下代码段使用 Node-API 值来完成等效操作:

napi_status status = napi_generic_failure;

// const obj = {}
napi_value obj, value;
status = napi_create_object(env, &obj);
if (status != napi_ok) return status;

// Create a napi_value for 123
status = napi_create_int32(env, 123, &value);
if (status != napi_ok) return status;

// obj.myProp = 123
status = napi_set_named_property(env, obj, "myProp", value);
if (status != napi_ok) return status; 

可以以类似的方式设置索引属性。 考虑以下 JavaScript 片段:

const arr = [];
arr[123] = 'hello'; 

可以通过以下代码段使用 Node-API 值来完成等效操作:

napi_status status = napi_generic_failure;

// const arr = [];
napi_value arr, value;
status = napi_create_array(env, &arr);
if (status != napi_ok) return status;

// Create a napi_value for 'hello'
status = napi_create_string_utf8(env, "hello", NAPI_AUTO_LENGTH, &value);
if (status != napi_ok) return status;

// arr[123] = 'hello';
status = napi_set_element(env, arr, 123, value);
if (status != napi_ok) return status; 

可以使用本节中描述的 API 检索属性。 考虑以下 JavaScript 片段:

const arr = [];
const value = arr[123]; 

以下是 Node-API 对应物的大致等价物:

napi_status status = napi_generic_failure;

// const arr = []
napi_value arr, value;
status = napi_create_array(env, &arr);
if (status != napi_ok) return status;

// const value = arr[123]
status = napi_get_element(env, arr, 123, &value);
if (status != napi_ok) return status; 

最后,出于性能原因,还可以在一个对象上定义多个属性。 考虑以下 JavaScript:

const obj = {};
Object.defineProperties(obj, {
  'foo': { value: 123, writable: true, configurable: true, enumerable: true },
  'bar': { value: 456, writable: true, configurable: true, enumerable: true },
}); 

以下是 Node-API 对应物的大致等价物:

napi_status status = napi_status_generic_failure;

// const obj = {};
napi_value obj;
status = napi_create_object(env, &obj);
if (status != napi_ok) return status;

// Create napi_values for 123 and 456
napi_value fooValue, barValue;
status = napi_create_int32(env, 123, &fooValue);
if (status != napi_ok) return status;
status = napi_create_int32(env, 456, &barValue);
if (status != napi_ok) return status;

// Set the properties
napi_property_descriptor descriptors[] = {
  { "foo", NULL, NULL, NULL, NULL, fooValue, napi_writable | napi_configurable, NULL },
  { "bar", NULL, NULL, NULL, NULL, barValue, napi_writable | napi_configurable, NULL }
}
status = napi_define_properties(env,
                                obj,
                                sizeof(descriptors) / sizeof(descriptors[0]),
                                descriptors);
if (status != napi_ok) return status; 

结构#

napi_property_attributes#
typedef enum {
  napi_default = 0,
  napi_writable = 1 << 0,
  napi_enumerable = 1 << 1,
  napi_configurable = 1 << 2,

  // Used with napi_define_class to distinguish static properties
  // from instance properties. Ignored by napi_define_properties.
  napi_static = 1 << 10,

  // Default for class methods.
  napi_default_method = napi_writable | napi_configurable,

  // Default for object properties, like in JS obj[prop].
  napi_default_jsproperty = napi_writable |
                          napi_enumerable |
                          napi_configurable,
} napi_property_attributes; 

napi_property_attributes 是用于控制在 JavaScript 对象上设置的属性行为的标志。 除 napi_static 外,它们对应于 ECMAScript 语言规范第 6.1.7.1 节 中列出的属性。 它们可以是以下一个或多个位标志:

  • napi_default: 没有在属性上设置显式属性。 默认情况下,属性是只读的,不可枚举且不可配置。
  • napi_writable: 该属性是可写的。
  • napi_enumerable: 该属性是可枚举的。
  • napi_configurable: 该属性可按照 ECMAScript 语言规范第 6.1.7.1 节 中的定义进行配置。
  • napi_static: 该属性将被定义为类的静态属性,而不是默认的实例属性。 这仅由 napi_define_class 使用。 它被 napi_define_properties 忽略。
  • napi_default_method: 就像 JS 类中的方法一样,该属性是可配置和可写的,但不可枚举。
  • napi_default_jsproperty: 就像 JavaScript 中通过赋值设置的属性一样,属性是可写、可枚举和可配置的。

napi_property_descriptor#
typedef struct {
  // One of utf8name or name should be NULL.
  const char* utf8name;
  napi_value name;

  napi_callback method;
  napi_callback getter;
  napi_callback setter;
  napi_value value;

  napi_property_attributes attributes;
  void* data;
} napi_property_descriptor; 
  • utf8name: 描述属性键的可选字符串,编码为 UTF8。 必须为房产提供 utf8namename 之一。
  • name: 可选的 napi_value,指向用作属性键的 JavaScript 字符串或符号。 必须为房产提供 utf8namename 之一。
  • value: 如果属性是数据属性,则通过属性的 get 访问检索到的值。 如果传入,则将 gettersettermethoddata 设置为 NULL(因为不会使用这些成员)。
  • getter: 执行对属性的获取访问时调用的函数。 如果传入,则将 valuemethod 设置为 NULL(因为不会使用这些成员)。 当从 JavaScript 代码访问属性时(或者如果使用 Node-API 调用执行对属性的获取),运行时将隐式调用给定函数。 napi_callback 提供了更多详细信息。
  • setter: 执行属性的设置访问时调用的函数。 如果传入,则将 valuemethod 设置为 NULL(因为不会使用这些成员)。 当从 JavaScript 代码设置属性时(或者如果使用 Node-API 调用执行属性设置),运行时将隐式调用给定函数。 napi_callback 提供了更多详细信息。
  • method: 设置此项使属性描述符对象的 value 属性成为 method 表示的 JavaScript 函数。 如果传入,则将 valuegettersetter 设置为 NULL(因为不会使用这些成员)。 napi_callback 提供了更多详细信息。
  • attributes: 与特定属性关联的属性。 参见 napi_property_attributes
  • data: 如果调用此函数,回调数据将传递到 methodgettersetter

函数#

napi_get_property_names#
napi_status napi_get_property_names(napi_env env,
                                    napi_value object,
                                    napi_value* result); 
  • [in] env: 调用 Node-API 调用的环境。
  • [in] object: 从中检索属性的对象。
  • [out] result: 一个 napi_value,表示一个 JavaScript 值数组,这些值表示对象的属性名称。 API 可用于使用 napi_get_array_lengthnapi_get_element 迭代 result

如果 API 成功,则返回 napi_ok

此 API 以字符串数组的形式返回 object 的可枚举属性的名称。 key 为符号的 object 的属性将不会被包含在内。

napi_get_all_property_names#
napi_get_all_property_names(napi_env env,
                            napi_value object,
                            napi_key_collection_mode key_mode,
                            napi_key_filter key_filter,
                            napi_key_conversion key_conversion,
                            napi_value* result); 
  • [in] env: 调用 Node-API 调用的环境。
  • [in] object: 从中检索属性的对象。
  • [in] key_mode: 是否也检索原型属性。
  • [in] key_filter: 要检索哪些属性(可枚举/可读/可写)。
  • [in] key_conversion: 是否将编号的属性键转换为字符串。
  • [out] result: 一个 napi_value,表示一个 JavaScript 值数组,这些值表示对象的属性名称。 napi_get_array_lengthnapi_get_element 可用于迭代 result

如果 API 成功,则返回 napi_ok

此 API 返回一个数组,其中包含此对象的可用属性的名称。

napi_set_property#
napi_status napi_set_property(napi_env env,
                              napi_value object,
                              napi_value key,
                              napi_value value); 
  • [in] env: 调用 Node-API 调用的环境。
  • [in] object: 要对其设置属性的对象。
  • [in] key: 要设置的属性的名称。
  • [in] value: 属性值。

如果 API 成功,则返回 napi_ok

该 API 在传入的 Object 上设置了一个属性。

napi_get_property#
napi_status napi_get_property(napi_env env,
                              napi_value object,
                              napi_value key,
                              napi_value* result); 
  • [in] env: 调用 Node-API 调用的环境。
  • [in] object: 从中检索属性的对象。
  • [in] key: 要检索的属性的名称。
  • [out] result: 属性的值。

如果 API 成功,则返回 napi_ok

此 API 从传入的 Object 中获取请求的属性。

napi_has_property#
napi_status napi_has_property(napi_env env,
                              napi_value object,
                              napi_value key,
                              bool* result); 
  • [in] env: 调用 Node-API 调用的环境。
  • [in] object: 要查询的对象。
  • [in] key: 要检查其存在的属性的名称。
  • [out] result: 该属性是否存在于对象上。

如果 API 成功,则返回 napi_ok

此 API 检查传入的 Object 是否具有命名属性。

napi_delete_property#
napi_status napi_delete_property(napi_env env,
                                 napi_value object,
                                 napi_value key,
                                 bool* result); 
  • [in] env: 调用 Node-API 调用的环境。
  • [in] object: 要查询的对象。
  • [in] key: 要删除的属性的名称。
  • [out] result: 属性删除是否成功。 result 可以选择性地通过传递 NULL 来忽略。

如果 API 成功,则返回 napi_ok

此 API 尝试从 object 中删除 key 自己的属性。

napi_has_own_property#
napi_status napi_has_own_property(napi_env env,
                                  napi_value object,
                                  napi_value key,
                                  bool* result); 
  • [in] env: 调用 Node-API 调用的环境。
  • [in] object: 要查询的对象。
  • [in] key: 要检查其存在的自有属性的名称。
  • [out] result: 对象上是否存在自己的属性。

如果 API 成功,则返回 napi_ok

此 API 检查传入的 Object 是否具有命名的自己的属性。 key 必须是 stringsymbol,否则将抛出错误。 Node-API 不会执行任何数据类型之间的转换。

napi_set_named_property#
napi_status napi_set_named_property(napi_env env,
                                    napi_value object,
                                    const char* utf8Name,
                                    napi_value value); 
  • [in] env: 调用 Node-API 调用的环境。
  • [in] object: 要对其设置属性的对象。
  • [in] utf8Name: 要设置的属性的名称。
  • [in] value: 属性值。

如果 API 成功,则返回 napi_ok

此方法等效于使用从作为 utf8Name 传入的字符串创建的 napi_value 调用 napi_set_property

napi_get_named_property#
napi_status napi_get_named_property(napi_env env,
                                    napi_value object,
                                    const char* utf8Name,
                                    napi_value* result); 
  • [in] env: 调用 Node-API 调用的环境。
  • [in] object: 从中检索属性的对象。
  • [in] utf8Name: 要获取的属性的名称。
  • [out] result: 属性的值。

如果 API 成功,则返回 napi_ok

此方法等效于使用从作为 utf8Name 传入的字符串创建的 napi_value 调用 napi_get_property

napi_has_named_property#
napi_status napi_has_named_property(napi_env env,
                                    napi_value object,
                                    const char* utf8Name,
                                    bool* result); 
  • [in] env: 调用 Node-API 调用的环境。
  • [in] object: 要查询的对象。
  • [in] utf8Name: 要检查其存在的属性的名称。
  • [out] result: 该属性是否存在于对象上。

如果 API 成功,则返回 napi_ok

此方法等效于使用从作为 utf8Name 传入的字符串创建的 napi_value 调用 napi_has_property

napi_set_element#
napi_status napi_set_element(napi_env env,
                             napi_value object,
                             uint32_t index,
                             napi_value value); 
  • [in] env: 调用 Node-API 调用的环境。
  • [in] object: 从中设置属性的对象。
  • [in] index: 要设置的属性的索引。
  • [in] value: 属性值。

如果 API 成功,则返回 napi_ok

该 API 在传入的 Object 上设置一个元素。

napi_get_element#
napi_status napi_get_element(napi_env env,
                             napi_value object,
                             uint32_t index,
                             napi_value* result); 
  • [in] env: 调用 Node-API 调用的环境。
  • [in] object: 从中检索属性的对象。
  • [in] index: 要获取的属性的索引。
  • [out] result: 属性的值。

如果 API 成功,则返回 napi_ok

此 API 获取请求索引处的元素。

napi_has_element#
napi_status napi_has_element(napi_env env,
                             napi_value object,
                             uint32_t index,
                             bool* result); 
  • [in] env: 调用 Node-API 调用的环境。
  • [in] object: 要查询的对象。
  • [in] index: 要检查其存在的属性的索引。
  • [out] result: 该属性是否存在于对象上。

如果 API 成功,则返回 napi_ok

如果传入的 Object 在请求的索引处有一个元素,则此 API 返回。

napi_delete_element#
napi_status napi_delete_element(napi_env env,
                                napi_value object,
                                uint32_t index,
                                bool* result); 
  • [in] env: 调用 Node-API 调用的环境。
  • [in] object: 要查询的对象。
  • [in] index: 要删除的属性的索引。
  • [out] result: 删除元素是否成功。 result 可以选择性地通过传递 NULL 来忽略。

如果 API 成功,则返回 napi_ok

此 API 尝试从 object 中删除指定的 index

napi_define_properties#
napi_status napi_define_properties(napi_env env,
                                   napi_value object,
                                   size_t property_count,
                                   const napi_property_descriptor* properties); 
  • [in] env: 调用 Node-API 调用的环境。
  • [in] object: 从中检索属性的对象。
  • [in] property_count: properties 数组中的元素数。
  • [in] properties: 属性描述符数组。

如果 API 成功,则返回 napi_ok

此方法允许在给定对象上高效定义多个属性。 属性是使用属性描述符定义的(参见 napi_property_descriptor)。 给定一组此类属性描述符,此 API 将一次设置一个对象的属性,如 DefineOwnProperty() 所定义(在 ECMA-262 规范的 第 9.1.6 节 中描述)。

napi_object_freeze#
napi_status napi_object_freeze(napi_env env,
                               napi_value object); 
  • [in] env: 调用 Node-API 调用的环境。
  • [in] object: 要冻结的对象。

如果 API 成功,则返回 napi_ok

此方法冻结给定的对象。 这可以防止向其添加新属性,删除现有属性,防止更改现有属性的可枚举性、可配置性或可写性,并防止更改现有属性的值。 它还可以防止对象的原型被更改。 这在 ECMA-262 规范的 第 19.1.2.6 节 中进行了描述。

napi_object_seal#
napi_status napi_object_seal(napi_env env,
                             napi_value object); 
  • [in] env: 调用 Node-API 调用的环境。
  • [in] object: 要封印的对象。

如果 API 成功,则返回 napi_ok

此方法密封给定的对象。 这可以防止向其添加新属性,以及将所有现有属性标记为不可配置。 这在 ECMA-262 规范的 第 19.1.2.20 节 中进行了描述。

使用 JavaScript 函数#

Node-API 提供了一组 API,允许 JavaScript 代码回调原生代码。 支持回调原生代码的 Node-API 接受由 napi_callback 类型表示的回调函数。 当 JavaScript VM 回调原生代码时,将调用提供的 napi_callback 函数。 本节中记录的 API 允许回调函数执行以下操作:

  • 获取有关调用回调的上下文的信息。
  • 获取传递给回调的参数。
  • 从回调中返回 napi_value

此外,Node-API 提供了一组函数,允许从原生代码调用 JavaScript 函数。 可以像常规 JavaScript 函数调用一样调用函数,也可以作为构造函数调用。

通过 napi_property_descriptor 项的 data 字段传递给此 API 的任何非 NULL 数据都可以与 object 相关联,并在 object 通过将 object 和数据传递给 napi_add_finalizer 进行垃圾回收时释放。

napi_call_function#

NAPI_EXTERN napi_status napi_call_function(napi_env env,
                                           napi_value recv,
                                           napi_value func,
                                           size_t argc,
                                           const napi_value* argv,
                                           napi_value* result); 
  • [in] env: 调用 API 的环境。
  • [in] recv: 传递给被调用函数的 this 值。
  • [in] func: napi_value 表示要调用的 JavaScript 函数。
  • [in] argc: argv 数组中的元素数。
  • [in] argv: napi_values 的数组,表示作为参数传递给函数的 JavaScript 值。
  • [out] result: napi_value 表示返回的 JavaScript 对象。

如果 API 成功,则返回 napi_ok

此方法允许从原生附加组件调用 JavaScript 函数对象。 这是从加载项的原生代码回调到 JavaScript 的主要机制。 有关在异步操作后调用 JavaScript 的特殊情况,请参阅 napi_make_callback

示例用例可能如下所示。 考虑以下 JavaScript 片段:

function AddTwo(num) {
  return num + 2;
}
global.AddTwo = AddTwo; 

然后,可以使用以下代码从原生附加组件调用上述函数:

// Get the function named "AddTwo" on the global object
napi_value global, add_two, arg;
napi_status status = napi_get_global(env, &global);
if (status != napi_ok) return;

status = napi_get_named_property(env, global, "AddTwo", &add_two);
if (status != napi_ok) return;

// const arg = 1337
status = napi_create_int32(env, 1337, &arg);
if (status != napi_ok) return;

napi_value* argv = &arg;
size_t argc = 1;

// AddTwo(arg);
napi_value return_val;
status = napi_call_function(env, global, add_two, argc, argv, &return_val);
if (status != napi_ok) return;

// Convert the result back to a native type
int32_t result;
status = napi_get_value_int32(env, return_val, &result);
if (status != napi_ok) return; 

napi_create_function#

napi_status napi_create_function(napi_env env,
                                 const char* utf8name,
                                 size_t length,
                                 napi_callback cb,
                                 void* data,
                                 napi_value* result); 
  • [in] env: 调用 API 的环境。
  • [in] utf8Name: 编码为 UTF8 的函数的可选名称。 这在 JavaScript 中是可见的,作为新函数对象的 name 属性。
  • [in] length: utf8name 的长度(以字节为单位)或 NAPI_AUTO_LENGTH(如果以 null 结尾)。
  • [in] cb: 调用此函数对象时应调用的原生函数。 napi_callback 提供了更多详细信息。
  • [in] data: 用户提供的数据上下文。 这将在稍后调用时传回函数。
  • [out] result: napi_value 表示新创建函数的 JavaScript 函数对象。

如果 API 成功,则返回 napi_ok

此 API 允许插件作者以原生代码创建函数对象。 这是允许从 JavaScript 调用加载项的原生代码的主要机制。

在此调用之后,新创建的函数不会自动从脚本中可见。 相反,必须在 JavaScript 可见的任何对象上显式设置属性,以便可以从脚本访问该函数。

为了将函数公开为附加模块导出的一部分,请在导出对象上设置新创建的函数。 示例模块可能如下所示:

napi_value SayHello(napi_env env, napi_callback_info info) {
  printf("Hello\n");
  return NULL;
}

napi_value Init(napi_env env, napi_value exports) {
  napi_status status;

  napi_value fn;
  status = napi_create_function(env, NULL, 0, SayHello, NULL, &fn);
  if (status != napi_ok) return NULL;

  status = napi_set_named_property(env, exports, "sayHello", fn);
  if (status != napi_ok) return NULL;

  return exports;
}

NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) 

鉴于以上代码,可以从 JavaScript 中使用附加组件,如下所示:

const myaddon = require('./addon');
myaddon.sayHello(); 

传递给 require() 的字符串是 binding.gyp 中负责创建 .node 文件的目标的名称。

通过 data 参数传递给此 API 的任何非 NULL 数据都可以与生成的 JavaScript 函数(在 result 参数中返回)相关联,并在通过传递 JavaScript 函数和数据对函数进行垃圾回收时释放 到 napi_add_finalizer

JavaScript Function 在 ECMAScript 语言规范的 第 19.2 节 中描述。

napi_get_cb_info#

napi_status napi_get_cb_info(napi_env env,
                             napi_callback_info cbinfo,
                             size_t* argc,
                             napi_value* argv,
                             napi_value* thisArg,
                             void** data) 
  • [in] env: 调用 API 的环境。
  • [in] cbinfo: 传递给回调函数的回调信息。
  • [in-out] argc: 指定所提供的 argv 数组的长度并接收参数的实际计数。 argc 可以选择性地通过传递 NULL 来忽略。
  • [out] argv: 参数将被复制到的 napi_value 的 C 数组。 如果参数数量多于提供的数量,则只复制请求数量的参数。 如果提供的参数比声明的少,则 argv 的其余部分将填充代表 undefinednapi_value 值。 argv 可以选择性地通过传递 NULL 来忽略。
  • [out] thisArg: 接收调用的 JavaScript this 参数。 thisArg 可以选择性地通过传递 NULL 来忽略。
  • [out] data: 接收回调的数据指针。 data 可以选择性地通过传递 NULL 来忽略。

如果 API 成功,则返回 napi_ok

此方法在回调函数中用于检索有关调用的详细信息,例如来自给定回调信息的参数和 this 指针。

napi_get_new_target#

napi_status napi_get_new_target(napi_env env,
                                napi_callback_info cbinfo,
                                napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [in] cbinfo: 传递给回调函数的回调信息。
  • [out] result: 构造函数调用的 new.target

如果 API 成功,则返回 napi_ok

此 API 返回构造函数调用的 new.target。 如果当前回调不是构造函数调用,则结果为 NULL

napi_new_instance#

napi_status napi_new_instance(napi_env env,
                              napi_value cons,
                              size_t argc,
                              napi_value* argv,
                              napi_value* result) 
  • [in] env: 调用 API 的环境。
  • [in] cons: napi_value 表示要作为构造函数调用的 JavaScript 函数。
  • [in] argc: argv 数组中的元素数。
  • [in] argv: JavaScript 值数组 napi_value 表示构造函数的参数。 如果 argc 为零,则可以通过传入 NULL 来省略此参数。
  • [out] result: napi_value 表示返回的 JavaScript 对象,在本例中是构造的对象。

此方法用于使用给定的 napi_value 表示对象的构造函数来实例化新的 JavaScript 值。 例如,考虑以下片段:

function MyObject(param) {
  this.param = param;
}

const arg = 'hello';
const value = new MyObject(arg); 

可以使用以下代码片段在 Node-API 中近似计算以下内容:

// Get the constructor function MyObject
napi_value global, constructor, arg, value;
napi_status status = napi_get_global(env, &global);
if (status != napi_ok) return;

status = napi_get_named_property(env, global, "MyObject", &constructor);
if (status != napi_ok) return;

// const arg = "hello"
status = napi_create_string_utf8(env, "hello", NAPI_AUTO_LENGTH, &arg);
if (status != napi_ok) return;

napi_value* argv = &arg;
size_t argc = 1;

// const value = new MyObject(arg)
status = napi_new_instance(env, constructor, argc, argv, &value); 

如果 API 成功,则返回 napi_ok

对象封装#

Node-API 为 "wrap" C++ 类和实例提供了一种方法,以便可以从 JavaScript 调用类构造函数和方法。

  1. napi_define_class API 定义了一个 JavaScript 类,其中包含与 C++ 类对应的构造函数、静态属性和方法以及实例属性和方法。
  2. 当 JavaScript 代码调用构造函数时,构造函数回调使用 napi_wrap 将新的 C++ 实例封装在 JavaScript 对象中,然后返回封装对象。
  3. 当 JavaScript 代码调用类上的方法或属性访问器时,将调用相应的 napi_callback C++ 函数。 对于实例回调,napi_unwrap 获取作为调用目标的 C++ 实例。

对于封装对象,可能很难区分在类原型上调用的函数和在类实例上调用的函数。 用于解决此问题的一种常见模式是保存对类构造函数的持久引用,以供以后进行 instanceof 检查。

napi_value MyClass_constructor = NULL;
status = napi_get_reference_value(env, MyClass::es_constructor, &MyClass_constructor);
assert(napi_ok == status);
bool is_instance = false;
status = napi_instanceof(env, es_this, MyClass_constructor, &is_instance);
assert(napi_ok == status);
if (is_instance) {
  // napi_unwrap() ...
} else {
  // otherwise...
} 

一旦不再需要引用,就必须将其释放。

在某些情况下,napi_instanceof() 不足以确保 JavaScript 对象是某种原生类型的封装器。 尤其是当封装的 JavaScript 对象通过静态方法而不是作为原型方法的 this 值传递回插件时。 在这种情况下,它们有可能被错误地解包。

const myAddon = require('./build/Release/my_addon.node');

// `openDatabase()` returns a JavaScript object that wraps a native database
// handle.
const dbHandle = myAddon.openDatabase();

// `query()` returns a JavaScript object that wraps a native query handle.
const queryHandle = myAddon.query(dbHandle, 'Gimme ALL the things!');

// There is an accidental error in the line below. The first parameter to
// `myAddon.queryHasRecords()` should be the database handle (`dbHandle`), not
// the query handle (`query`), so the correct condition for the while-loop
// should be
//
// myAddon.queryHasRecords(dbHandle, queryHandle)
//
while (myAddon.queryHasRecords(queryHandle, dbHandle)) {
  // retrieve records
} 

在上面的示例中,myAddon.queryHasRecords() 是一个接受两个参数的方法。 第一个是数据库句柄,第二个是查询句柄。 在内部,它解开第一个参数并将结果指针转换为原生数据库句柄。 然后它解包第二个参数并将结果指针转换为查询句柄。 如果参数以错误的顺序传递,转换将起作用,但是,底层数据库操作很可能会失败,甚至会导致无效的内存访问。

为了确保从第一个参数中检索到的指针确实是指向数据库句柄的指针,并且类似地,从第二个参数中检索到的指针确实是指向查询句柄的指针,queryHasRecords() 的实现必须执行类型验证。 在 napi_ref 中保留实例化数据库句柄的 JavaScript 类构造函数和实例化查询句柄的构造函数会有所帮助,因为 napi_instanceof() 然后可用于确保传递到 queryHashRecords() 的实例确实是正确的类型。

不幸的是,napi_instanceof() 不能防止原型操作。 例如,数据库句柄实例的原型可以设置为查询句柄实例的构造函数的原型。 在这种情况下,数据库句柄实例可以作为查询句柄实例出现,它将通过查询句柄实例的 napi_instanceof() 测试,同时仍包含指向数据库句柄的指针。

为此,Node-API 提供了类型标记功能。

类型标签是插件独有的 128 位整数。 Node-API 提供了用于存储类型标签的 napi_type_tag 结构。 当这样的值与存储在 napi_valuenapi_type_tag_object() 中的 JavaScript 对象或 外部的 一起传递时,JavaScript 对象将是带有类型标记的 "marked"。 "mark" 在 JavaScript 端是不可见的。 当 JavaScript 对象到达原生绑定时,可以使用 napi_check_object_type_tag() 和原始类型标签来确定 JavaScript 对象之前是否是带有类型标签的 "marked"。 这创建了比 napi_instanceof() 可以提供的保真度更高的类型检查功能,因为这种类型标记在原型操作和插件卸载/重新加载后仍然存在。

继续上面的例子,下面的框架插件实现说明了 napi_type_tag_object()napi_check_object_type_tag() 的使用。

// This value is the type tag for a database handle. The command
//
//   uuidgen | sed -r -e 's/-//g' -e 's/(.{16})(.*)/0x\1, 0x\2/'
//
// can be used to obtain the two values with which to initialize the structure.
static const napi_type_tag DatabaseHandleTypeTag = {
  0x1edf75a38336451d, 0xa5ed9ce2e4c00c38
};

// This value is the type tag for a query handle.
static const napi_type_tag QueryHandleTypeTag = {
  0x9c73317f9fad44a3, 0x93c3920bf3b0ad6a
};

static napi_value
openDatabase(napi_env env, napi_callback_info info) {
  napi_status status;
  napi_value result;

  // Perform the underlying action which results in a database handle.
  DatabaseHandle* dbHandle = open_database();

  // Create a new, empty JS object.
  status = napi_create_object(env, &result);
  if (status != napi_ok) return NULL;

  // Tag the object to indicate that it holds a pointer to a `DatabaseHandle`.
  status = napi_type_tag_object(env, result, &DatabaseHandleTypeTag);
  if (status != napi_ok) return NULL;

  // Store the pointer to the `DatabaseHandle` structure inside the JS object.
  status = napi_wrap(env, result, dbHandle, NULL, NULL, NULL);
  if (status != napi_ok) return NULL;

  return result;
}

// Later when we receive a JavaScript object purporting to be a database handle
// we can use `napi_check_object_type_tag()` to ensure that it is indeed such a
// handle.

static napi_value
query(napi_env env, napi_callback_info info) {
  napi_status status;
  size_t argc = 2;
  napi_value argv[2];
  bool is_db_handle;

  status = napi_get_cb_info(env, info, &argc, argv, NULL, NULL);
  if (status != napi_ok) return NULL;

  // Check that the object passed as the first parameter has the previously
  // applied tag.
  status = napi_check_object_type_tag(env,
                                      argv[0],
                                      &DatabaseHandleTypeTag,
                                      &is_db_handle);
  if (status != napi_ok) return NULL;

  // Throw a `TypeError` if it doesn't.
  if (!is_db_handle) {
    // Throw a TypeError.
    return NULL;
  }
} 

napi_define_class#

napi_status napi_define_class(napi_env env,
                              const char* utf8name,
                              size_t length,
                              napi_callback constructor,
                              void* data,
                              size_t property_count,
                              const napi_property_descriptor* properties,
                              napi_value* result); 
  • [in] env: 调用 API 的环境。
  • [in] utf8name: JavaScript 构造函数的名称。 为清楚起见,建议在封装 C++ 类时使用 C++ 类名。
  • [in] length: utf8name 的长度(以字节为单位)或 NAPI_AUTO_LENGTH(如果以 null 结尾)。
  • [in] constructor: 处理类的构造实例的回调函数。 封装 C++ 类时,此方法必须是具有 napi_callback 签名的静态成员。 不能使用 C++ 类构造函数。 napi_callback 提供了更多详细信息。
  • [in] data: 作为回调信息的 data 属性传递给构造函数回调的可选数据。
  • [in] property_count: properties 数组参数中的项数。
  • [in] properties: 描述类静态和实例数据属性、访问器和方法的属性描述符数组 请参见 napi_property_descriptor
  • [out] result: 表示类的构造函数的 napi_value

如果 API 成功,则返回 napi_ok

定义一个 JavaScript 类,包括:

  • 具有类名的 JavaScript 构造函数。 当封装相应的 C++ 类时,通过 constructor 传递的回调可用于实例化一个新的 C++ 类实例,然后将其放置在使用 napi_wrap 构造的 JavaScript 对象实例中。
  • 构造函数上的属性,其实现可以调用 C++ 类的相应静态数据属性、访问器和方法(由具有 napi_static 属性的属性描述符定义)。
  • 构造函数的 prototype 对象的属性。 封装 C++ 类时,在检索放置在 JavaScript 对象实例中的 C++ 类实例后,可以从属性描述符中给定的静态函数调用 C++ 类的非静态数据属性、访问器和方法,而无需使用 napi_static 属性 napi_unwrap

封装 C++ 类时,通过 constructor 传递的 C++ 构造函数回调应该是调用实际类构造函数的类的静态方法,然后将新的 C++ 实例封装在 JavaScript 对象中,并返回封装器对象。 详见 napi_wrap

napi_define_class 返回的 JavaScript 构造函数通常被保存并在以后用于从原生代码构造类的新实例,和/或检查提供的值是否是类的实例。 In that case, to prevent the function value from being garbage-collected, a strong persistent reference to it can be created using napi_create_reference, ensuring that the reference count is kept >= 1.

通过 data 参数或 napi_property_descriptor 数组项的 data 字段传递给此 API 的任何非 NULL 数据都可以与生成的 JavaScript 构造函数(在 result 参数中返回)相关联,并在类为垃圾时释放 - 通过将 JavaScript 函数和数据传递给 napi_add_finalizer 来收集。

napi_wrap#

napi_status napi_wrap(napi_env env,
                      napi_value js_object,
                      void* native_object,
                      napi_finalize finalize_cb,
                      void* finalize_hint,
                      napi_ref* result); 
  • [in] env: 调用 API 的环境。
  • [in] js_object: 将成为原生对象封装器的 JavaScript 对象。
  • [in] native_object: 将封装在 JavaScript 对象中的原生实例。
  • [in] finalize_cb: 可选的原生回调,可用于在 JavaScript 对象被垃圾回收时释放原生实例。 napi_finalize 提供了更多详细信息。
  • [in] finalize_hint: 传递给完成回调的可选上下文提示。
  • [out] result: 对封装对象的可选引用。

如果 API 成功,则返回 napi_ok

在 JavaScript 对象中封装原生实例。 稍后可以使用 napi_unwrap() 检索原生实例。

当 JavaScript 代码调用使用 napi_define_class() 定义的类的构造函数时,将调用构造函数的 napi_callback。 构造原生类的实例后,回调必须调用 napi_wrap() 以将新构造的实例封装在已创建的 JavaScript 对象中,该对象是构造函数回调的 this 参数。 (this 对象是从构造函数的 prototype 创建的,因此它已经具有所有实例属性和方法的定义。)

通常在封装类实例时,应该提供一个终结回调,它只是删除作为终结回调的 data 参数接收的原生实例。

可选的返回引用最初是弱引用,这意味着它的引用计数为 0。 通常,在需要实例保持有效的异步操作期间,此引用计数会临时增加。

警告_: 可选的返回引用(如果获得)应仅通过 napi_delete_reference 删除以响应最终回调调用。 如果在此之前删除它,则可能永远不会调用 finalize 回调。 因此,在获取引用时,还需要一个 finalize 回调,以便能够正确处理引用。

终结器回调可能会被延迟,留下一个窗口,其中对象已被垃圾收集(并且弱引用无效)但尚未调用终结器。 在 napi_wrap() 返回的弱引用上使用 napi_get_reference_value() 时,您仍应处理空结果。

对对象再次调用 napi_wrap() 将返回错误。 要将另一个原生实例与对象相关联,请先使用 napi_remove_wrap()

napi_unwrap#

napi_status napi_unwrap(napi_env env,
                        napi_value js_object,
                        void** result); 
  • [in] env: 调用 API 的环境。
  • [in] js_object: 与原生实例关联的对象。
  • [out] result: 指向封装的原生实例的指针。

如果 API 成功,则返回 napi_ok

使用 napi_wrap() 检索先前封装在 JavaScript 对象中的原生实例。

当 JavaScript 代码调用类上的方法或属性访问器时,将调用相应的 napi_callback。 如果回调用于实例方法或访问器,则回调的 this 参数是封装器对象; 然后可以通过在封装对象上调用 napi_unwrap() 来获得作为调用目标的封装 C++ 实例。

napi_remove_wrap#

napi_status napi_remove_wrap(napi_env env,
                             napi_value js_object,
                             void** result); 
  • [in] env: 调用 API 的环境。
  • [in] js_object: 与原生实例关联的对象。
  • [out] result: 指向封装的原生实例的指针。

如果 API 成功,则返回 napi_ok

使用 napi_wrap() 检索先前封装在 JavaScript 对象 js_object 中的原生实例并移除封装。 如果 finalize 回调与封装相关联,则当 JavaScript 对象被垃圾回收时将不再调用它。

napi_type_tag_object#

napi_status napi_type_tag_object(napi_env env,
                                 napi_value js_object,
                                 const napi_type_tag* type_tag); 
  • [in] env: 调用 API 的环境。
  • [in] js_object: 要标记的 JavaScript 对象或 外部的
  • [in] type_tag: 要标记对象的标签。

如果 API 成功,则返回 napi_ok

type_tag 指针的值与 JavaScript 对象或 外部的 相关联。 然后可以使用 napi_check_object_type_tag() 将附加到对象的标签与插件拥有的标签进行比较,以确保对象具有正确的类型。

如果对象已经有关联的类型标签,此 API 将返回 napi_invalid_arg

napi_check_object_type_tag#

napi_status napi_check_object_type_tag(napi_env env,
                                       napi_value js_object,
                                       const napi_type_tag* type_tag,
                                       bool* result); 
  • [in] env: 调用 API 的环境。
  • [in] js_object: 要检查其类型标记的 JavaScript 对象或 外部的
  • [in] type_tag: 用于比较在对象上找到的任何标签的标签。
  • [out] result: 给定的类型标签是否与对象上的类型标签匹配。 如果在对象上未找到类型标记,也会返回 false

如果 API 成功,则返回 napi_ok

将作为 type_tag 给出的指针与 js_object 上可以找到的任何指针进行比较。 如果在 js_object 上没有找到标签,或者如果找到标签但它与 type_tag 不匹配,则 result 设置为 false。 如果找到标签并且它与 type_tag 匹配,则将 result 设置为 true

napi_add_finalizer#

napi_status napi_add_finalizer(napi_env env,
                               napi_value js_object,
                               void* finalize_data,
                               napi_finalize finalize_cb,
                               void* finalize_hint,
                               napi_ref* result); 
  • [in] env: 调用 API 的环境。
  • [in] js_object: 原生数据将附加到的 JavaScript 对象。
  • [in] finalize_data: 要传递给 finalize_cb 的可选数据。
  • [in] finalize_cb: 当 JavaScript 对象被垃圾回收时,将用于释放原生数据的原生回调。 napi_finalize 提供了更多详细信息。
  • [in] finalize_hint: 传递给完成回调的可选上下文提示。
  • [out] result: 对 JavaScript 对象的可选引用。

如果 API 成功,则返回 napi_ok

添加 napi_finalize 回调,当 js_object 中的 JavaScript 对象被垃圾回收时调用。

可以在单个 JavaScript 对象上多次调用此 API。

警告_: 可选的返回引用(如果获得)应仅通过 napi_delete_reference 删除以响应最终回调调用。 如果在此之前删除它,则可能永远不会调用 finalize 回调。 因此,在获取引用时,还需要一个 finalize 回调,以便能够正确处理引用。

简单的异步操作#

插件模块通常需要利用 libuv 中的异步助手作为其实现的一部分。 这允许他们安排异步执行的工作,以便他们的方法可以在工作完成之前返回。 这使他们能够避免阻止 Node.js 应用程序的整体执行。

Node-API 为这些支持功能提供了一个 ABI 稳定的接口,涵盖了最常见的异步用例。

Node-API 定义了用于管理异步工作者的 napi_async_work 结构。 使用 napi_create_async_worknapi_delete_async_work 创建/删除实例。

executecomplete 回调函数将分别在执行程序准备好执行和完成任务时调用。

execute 函数应避免进行任何可能导致 JavaScript 执行或与 JavaScript 对象交互的 Node-API 调用。 大多数情况下,任何需要进行 Node-API 调用的代码都应该在 complete 回调中进行。 避免在执行回调中使用 napi_env 参数,因为它可能会执行 JavaScript。

这些函数实现了以下接口:

typedef void (*napi_async_execute_callback)(napi_env env,
                                            void* data);
typedef void (*napi_async_complete_callback)(napi_env env,
                                             napi_status status,
                                             void* data); 

调用这些方法时,传递的 data 参数将是传递给 napi_create_async_work 调用的插件提供的 void* 数据。

创建异步工作线程后,可以使用 napi_queue_async_work 函数排队等待执行:

napi_status napi_queue_async_work(napi_env env,
                                  napi_async_work work); 

如果需要在工作开始执行之前取消工作,则可以使用 napi_cancel_async_work

调用 napi_cancel_async_work 后,将调用状态值为 napi_cancelledcomplete 回调。 在 complete 回调调用之前不应删除该工作,即使它已被取消。

napi_create_async_work#

napi_status napi_create_async_work(napi_env env,
                                   napi_value async_resource,
                                   napi_value async_resource_name,
                                   napi_async_execute_callback execute,
                                   napi_async_complete_callback complete,
                                   void* data,
                                   napi_async_work* result); 
  • [in] env: 调用 API 的环境。
  • [in] async_resource: 与将传递给可能的 async_hooks init 钩子 的异步工作关联的可选对象。
  • [in] async_resource_name: 为 async_hooks API 公开的诊断信息提供的资源类型的标识符。
  • [in] execute: 应调用以异步执行逻辑的原生函数。 给定的函数从工作池线程调用,可以与主事件循环线程并行执行。
  • [in] complete: 异步逻辑完成或取消时将调用的原生函数。 从主事件循环线程调用给定的函数。 napi_async_complete_callback 提供了更多详细信息。
  • [in] data: 用户提供的数据上下文。 这将被传递回执行和完成功能。
  • [out] result: napi_async_work* 是新创建的异步工作的句柄。

如果 API 成功,则返回 napi_ok

此 API 分配用于异步执行逻辑的工作对象。 一旦不再需要该工作,应使用 napi_delete_async_work 将其释放。

async_resource_name 应该是一个以 null 结尾的 UTF-8 编码字符串。

async_resource_name 标识符由用户提供,应该代表正在执行的异步工作的类型。 还建议将命名空间应用于标识符,例如 通过包含模块名称。 有关详细信息,请参阅 async_hooks 文档

napi_delete_async_work#

napi_status napi_delete_async_work(napi_env env,
                                   napi_async_work work); 
  • [in] env: 调用 API 的环境。
  • [in] work: 调用 napi_create_async_work 返回的句柄。

如果 API 成功,则返回 napi_ok

此 API 释放先前分配的工作对象。

即使存在挂起的 JavaScript 异常,也可以调用此 API。

napi_queue_async_work#

napi_status napi_queue_async_work(napi_env env,
                                  napi_async_work work); 
  • [in] env: 调用 API 的环境。
  • [in] work: 调用 napi_create_async_work 返回的句柄。

如果 API 成功,则返回 napi_ok

此 API 请求安排执行先前分配的工作。 成功返回后,不得使用相同的 napi_async_work 项再次调用此 API,否则结果将不确定。

napi_cancel_async_work#

napi_status napi_cancel_async_work(napi_env env,
                                   napi_async_work work); 
  • [in] env: 调用 API 的环境。
  • [in] work: 调用 napi_create_async_work 返回的句柄。

如果 API 成功,则返回 napi_ok

如果尚未启动,此 API 会取消排队的工作。 如果已经开始执行,则无法取消,返回napi_generic_failure。 如果成功,将调用 complete 回调,状态值为 napi_cancelled。 在 complete 回调调用之前不应删除该工作,即使它已成功取消。

即使存在挂起的 JavaScript 异常,也可以调用此 API。

自定义异步操作#

上面简单的异步工作 API 可能并不适用于所有场景。 使用任何其他异步机制时,需要以下 API 来确保运行时正确跟踪异步操作。

napi_async_init#

napi_status napi_async_init(napi_env env,
                            napi_value async_resource,
                            napi_value async_resource_name,
                            napi_async_context* result) 
  • [in] env: 调用 API 的环境。
  • [in] async_resource: 与将传递给可能的 async_hooks init 钩子 and can be accessed by async_hooks.executionAsyncResource() 的异步工作关联的对象。
  • [in] async_resource_name: 为 async_hooks API 公开的诊断信息提供的资源类型的标识符。
  • [out] result: 初始化的异步上下文。

如果 API 成功,则返回 napi_ok

async_resource 对象需要保持活动状态直到 napi_async_destroy 才能使 async_hooks 相关 API 正常运行。 为了保持与之前版本的 ABI 兼容性,napi_async_context 没有维护对 async_resource 对象的强引用,以避免引入导致内存泄漏。 但是,如果 async_resourcenapi_async_contextnapi_async_destroy 销毁之前被 JavaScript 引擎垃圾回收,那么在使用 AsyncLocalStorage API 时调用 napi_async_context 相关 API(如 napi_open_callback_scopenapi_make_callback)可能会导致异步上下文丢失等问题。

为了保持与以前版本的 ABI 兼容性,为 async_resource 传递 NULL 不会导致错误。 但是,不建议这样做,因为这会导致 async_hooks init 钩子async_hooks.executionAsyncResource() 的结果不佳,因为底层 async_hooks 实现现在需要资源才能提供异步回调之间的链接。

napi_async_destroy#

napi_status napi_async_destroy(napi_env env,
                               napi_async_context async_context); 
  • [in] env: 调用 API 的环境。
  • [in] async_context: 要销毁的异步上下文。

如果 API 成功,则返回 napi_ok

即使存在挂起的 JavaScript 异常,也可以调用此 API。

napi_make_callback#

NAPI_EXTERN napi_status napi_make_callback(napi_env env,
                                           napi_async_context async_context,
                                           napi_value recv,
                                           napi_value func,
                                           size_t argc,
                                           const napi_value* argv,
                                           napi_value* result); 
  • [in] env: 调用 API 的环境。
  • [in] async_context: 调用回调的异步操作的上下文。 这通常应该是以前从 napi_async_init 获得的值。 为了保持与以前版本的 ABI 兼容性,为 async_context 传递 NULL 不会导致错误。 但是,这会导致异步钩子的错误操作。 潜在问题包括使用 AsyncLocalStorage API 时丢失异步上下文。
  • [in] recv: 传递给被调用函数的 this 值。
  • [in] func: napi_value 表示要调用的 JavaScript 函数。
  • [in] argc: argv 数组中的元素数。
  • [in] argv: JavaScript 值数组 napi_value 表示函数的参数。 如果 argc 为零,则可以通过传入 NULL 来省略此参数。
  • [out] result: napi_value 表示返回的 JavaScript 对象。

如果 API 成功,则返回 napi_ok

此方法允许从原生附加组件调用 JavaScript 函数对象。 这个 API 类似于 napi_call_function。 但是,它用于在从异步操作返回后(当堆栈上没有其他脚本时)从原生代码调用回 JavaScript。 它是 node::MakeCallback 的一个相当简单的封装器。

请注意,不必在 napi_async_complete_callback 中使用 napi_make_callback; 在这种情况下,回调的异步上下文已经设置好,因此直接调用 napi_call_function 就足够且合适了。 实现不使用 napi_create_async_work 的自定义异步行为时,可能需要使用 napi_make_callback 函数。

在回调期间由 JavaScript 在微任务队列上安排的任何 process.nextTick 或 Promises 在返回到 C/C++ 之前运行。

napi_open_callback_scope#

NAPI_EXTERN napi_status napi_open_callback_scope(napi_env env,
                                                 napi_value resource_object,
                                                 napi_async_context context,
                                                 napi_callback_scope* result) 
  • [in] env: 调用 API 的环境。
  • [in] resource_object: 与将传递给可能的 async_hooks init 钩子 的异步工作关联的对象。 此参数已被弃用,并在运行时被忽略。 请改用 napi_async_init 中的 async_resource 参数。
  • [in] context: 调用回调的异步操作的上下文。 这应该是之前从 napi_async_init 获得的值。
  • [out] result: 新创建的范围。

在某些情况下(例如,解决promise),在进行某些 Node-API 调用时,有必要具有与回调关联的等效范围。 如果堆栈上没有其他脚本,则可以使用 napi_open_callback_scopenapi_close_callback_scope 函数打开/关闭所需的范围。

napi_close_callback_scope#

NAPI_EXTERN napi_status napi_close_callback_scope(napi_env env,
                                                  napi_callback_scope scope) 
  • [in] env: 调用 API 的环境。
  • [in] scope: 要关闭的范围。

即使存在挂起的 JavaScript 异常,也可以调用此 API。

版本管理#

napi_get_node_version#

typedef struct {
  uint32_t major;
  uint32_t minor;
  uint32_t patch;
  const char* release;
} napi_node_version;

napi_status napi_get_node_version(napi_env env,
                                  const napi_node_version** version); 
  • [in] env: 调用 API 的环境。
  • [out] version: 指向 Node.js 本身版本信息的指针。

如果 API 成功,则返回 napi_ok

此函数用当前运行的 Node.js 的主要、次要和补丁版本填充 version 结构,并用 process.release.name 的值填充 release 字段。

返回的缓冲区是静态分配的,不需要释放。

napi_get_version#

napi_status napi_get_version(napi_env env,
                             uint32_t* result); 
  • [in] env: 调用 API 的环境。
  • [out] result: 支持的最高版本的 Node-API。

如果 API 成功,则返回 napi_ok

此 API 返回 Node.js 运行时支持的最高 Node-API 版本。 Node-API 计划是附加的,这样较新版本的 Node.js 可能会支持额外的 API 函数。 为了允许插件在使用支持它的 Node.js 版本运行时使用更新的功能,同时在使用不支持它的 Node.js 版本运行时提供回退行为:

  • 调用 napi_get_version() 以确定 API 是否可用。
  • 如果可用,使用 uv_dlsym() 动态加载指向函数的指针。
  • 使用动态加载的指针来调用函数。
  • 如果该函数不可用,请提供不使用该函数的替代实现。

内存管理#

napi_adjust_external_memory#

NAPI_EXTERN napi_status napi_adjust_external_memory(napi_env env,
                                                    int64_t change_in_bytes,
                                                    int64_t* result); 
  • [in] env: 调用 API 的环境。
  • [in] change_in_bytes: 由 JavaScript 对象保持活动状态的外部分配内存的变化。
  • [out] result: 调整值

如果 API 成功,则返回 napi_ok

此函数向 V8 指示由 JavaScript 对象保持活动状态的外部分配内存量(即,指向其自身由原生插件分配的内存的 JavaScript 对象)。 注册外部分配的内存将比其他方式更频繁地触发全局垃圾回收。

Promise#

Node-API 提供了创建 Promise 对象的工具,如 ECMA 规范的 第 25.4 节 中所述。 它将promise实现为一对对象。 当 napi_create_promise() 创建promise时,将创建 "deferred" 对象并与 Promise 一起返回。 延迟对象绑定到创建的 Promise,是使用 napi_resolve_deferred()napi_reject_deferred() 解析或拒绝 Promise 的唯一方法。 napi_create_promise() 创建的延迟对象由 napi_resolve_deferred()napi_reject_deferred() 释放。 Promise 对象可能会返回到 JavaScript,以便以通常的方式使用它。

例如,要创建一个 promise 并将其传递给异步 worker:

napi_deferred deferred;
napi_value promise;
napi_status status;

// Create the promise.
status = napi_create_promise(env, &deferred, &promise);
if (status != napi_ok) return NULL;

// Pass the deferred to a function that performs an asynchronous action.
do_something_asynchronous(deferred);

// Return the promise to JS
return promise; 

上面的函数 do_something_asynchronous() 将执行它的异步操作,然后它会解析或拒绝 deferred,从而结束promise并释放 deferred:

napi_deferred deferred;
napi_value undefined;
napi_status status;

// Create a value with which to conclude the deferred.
status = napi_get_undefined(env, &undefined);
if (status != napi_ok) return NULL;

// Resolve or reject the promise associated with the deferred depending on
// whether the asynchronous action succeeded.
if (asynchronous_action_succeeded) {
  status = napi_resolve_deferred(env, deferred, undefined);
} else {
  status = napi_reject_deferred(env, deferred, undefined);
}
if (status != napi_ok) return NULL;

// At this point the deferred has been freed, so we should assign NULL to it.
deferred = NULL; 

napi_create_promise#

napi_status napi_create_promise(napi_env env,
                                napi_deferred* deferred,
                                napi_value* promise); 
  • [in] env: 调用 API 的环境。
  • [out] deferred: 一个新创建的延迟对象,稍后可以传递给 napi_resolve_deferred()napi_reject_deferred() 以解析 resp。 拒绝相关的promise。
  • [out] promise: 与延迟对象关联的 JavaScript promise。

如果 API 成功,则返回 napi_ok

此 API 创建一个延迟对象和一个 JavaScript promise。

napi_resolve_deferred#

napi_status napi_resolve_deferred(napi_env env,
                                  napi_deferred deferred,
                                  napi_value resolution); 
  • [in] env: 调用 API 的环境。
  • [in] deferred: 要解析其关联promise的延迟对象。
  • [in] resolution: 用于解决 promise 的值。

此 API 通过与其关联的延迟对象来解析 JavaScript promise。 因此,它只能用于解析相应延迟对象可用的 JavaScript promise。 这实际上意味着promise必须是使用 napi_create_promise() 创建的,并且必须保留从该调用返回的延迟对象才能传递给此 API。

延迟对象在成功完成后被释放。

napi_reject_deferred#

napi_status napi_reject_deferred(napi_env env,
                                 napi_deferred deferred,
                                 napi_value rejection); 
  • [in] env: 调用 API 的环境。
  • [in] deferred: 要解析其关联promise的延迟对象。
  • [in] rejection: 用于拒绝 promise 的值。

此 API 通过与其关联的延迟对象拒绝 JavaScript promise。 因此,它只能用于拒绝相应延迟对象可用的 JavaScript promise。 这实际上意味着promise必须是使用 napi_create_promise() 创建的,并且必须保留从该调用返回的延迟对象才能传递给此 API。

延迟对象在成功完成后被释放。

napi_is_promise#

napi_status napi_is_promise(napi_env env,
                            napi_value value,
                            bool* is_promise); 
  • [in] env: 调用 API 的环境。
  • [in] value: 要检查的值
  • [out] is_promise: 表示promise是否为原生promise对象(即底层引擎创建的promise对象)的标志。

脚本执行#

Node-API 提供了一个 API,用于使用底层 JavaScript 引擎执行包含 JavaScript 的字符串。

napi_run_script#

NAPI_EXTERN napi_status napi_run_script(napi_env env,
                                        napi_value script,
                                        napi_value* result); 
  • [in] env: 调用 API 的环境。
  • [in] script: 包含要执行的脚本的 JavaScript 字符串。
  • [out] result: 执行脚本产生的值。

此函数执行一串 JavaScript 代码并返回其结果,但有以下注意事项:

  • eval 不同,此函数不允许脚本访问当前词法范围,因此也不允许访问 模块作用域,这意味着像 require 这样的伪全局变量将不可用。
  • 该脚本可以访问 全局作用域。 脚本中的函数和 var 声明将添加到 global 对象中。 使用 letconst 进行的变量声明将在全局可见,但不会添加到 global 对象中。
  • this 的值是脚本中的 global

libuv 事件循环#

Node-API 提供了一个函数,用于获取与特定 napi_env 关联的当前事件循环。

napi_get_uv_event_loop#

NAPI_EXTERN napi_status napi_get_uv_event_loop(napi_env env,
                                               struct uv_loop_s** loop); 
  • [in] env: 调用 API 的环境。
  • [out] loop: 当前的 libuv 循环实例。

异步线程安全函数调用#

JavaScript 函数通常只能从原生插件的主线程调用。 如果插件创建了额外的线程,则不得从这些线程调用需要 napi_envnapi_valuenapi_ref 的 Node-API 函数。

当插件有额外的线程并且需要根据这些线程完成的处理调用 JavaScript 函数时,这些线程必须与插件的主线程通信,以便主线程可以代表它们调用 JavaScript 函数。 线程安全函数 API 提供了一种简单的方法来执行此操作。

这些 API 提供了类型 napi_threadsafe_function 以及创建、销毁和调用该类型对象的 API。 napi_create_threadsafe_function() 创建对 napi_value 的持久引用,该引用包含可从多个线程调用的 JavaScript 函数。 调用异步发生。 这意味着调用 JavaScript 回调的值将被放置在一个队列中,并且对于队列中的每个值,最终将调用 JavaScript 函数。

创建 napi_threadsafe_function 后,可以提供 napi_finalize 回调。 当线程安全函数即将被销毁时,将在主线程上调用此回调。 它接收构造期间给出的上下文和最终数据,并提供在线程之后进行清理的机会,例如 通过调用 uv_thread_join()除了主循环线程外,在完成回调完成后,任何线程都不应使用线程安全函数。

在调用 napi_create_threadsafe_function() 期间给出的 context 可以从调用 napi_get_threadsafe_function_context() 的任何线程中检索。

调用线程安全的函数#

napi_call_threadsafe_function() 可用于启动对 JavaScript 的调用。 napi_call_threadsafe_function() 接受一个参数,该参数控制 API 是否以阻塞方式运行。 如果设置为 napi_tsfn_nonblocking,API 将以非阻塞方式运行,如果队列已满则返回 napi_queue_full,从而阻止数据成功添加到队列中。 如果设置为 napi_tsfn_blocking,API 将阻塞,直到队列中有可用空间。 如果创建的线程安全函数的最大队列大小为 0,则 napi_call_threadsafe_function() 永远不会阻塞。

不应从 JavaScript 线程使用 napi_tsfn_blocking 调用 napi_call_threadsafe_function(),因为如果队列已满,可能会导致 JavaScript 线程死锁。

对 JavaScript 的实际调用由通过 call_js_cb 参数给出的回调控制。 对于通过成功调用 napi_call_threadsafe_function() 放入队列中的每个值,在主线程上调用 call_js_cb 一次。 如果没有给出这样的回调,将使用默认回调,并且生成的 JavaScript 调用将没有参数。 call_js_cb 回调在其参数中接收要作为 napi_value 调用的 JavaScript 函数,以及创建 napi_threadsafe_function 时使用的 void* 上下文指针,以及由其中一个辅助线程创建的下一个数据指针。 然后,回调可以使用诸如 napi_call_function() 之类的 API 来调用 JavaScript。

回调也可以在 envcall_js_cb 都设置为 NULL 的情况下调用,以指示不再可能调用 JavaScript,而项目仍保留在可能需要释放的队列中。 这通常发生在 Node.js 进程退出而线程安全功能仍处于活动状态时。

没有必要通过 napi_make_callback() 调用 JavaScript,因为 Node-API 在适合回调的上下文中运行 call_js_cb

线程安全函数的引用计数#

napi_threadsafe_function 对象存在期间,可以将线程添加到 napi_threadsafe_function 对象或从中删除。 因此,除了在创建时指定线程的初始数量外,还可以调用 napi_acquire_threadsafe_function 来指示新线程将开始使用线程安全函数。 同样,可以调用 napi_release_threadsafe_function 来指示现有线程将停止使用线程安全函数。

当使用该对象的每个线程调用 napi_release_threadsafe_function() 或收到 napi_closing 的返回状态以响应对 napi_call_threadsafe_function 的调用时,napi_threadsafe_function 对象将被销毁。 在 napi_threadsafe_function 被销毁之前队列被清空。 napi_release_threadsafe_function() 应该是与给定的 napi_threadsafe_function 一起进行的最后一次 API 调用,因为在调用完成后,无法保证 napi_threadsafe_function 仍然被分配。 出于同样的原因,在收到 napi_closing 的返回值以响应对 napi_call_threadsafe_function 的调用后,不要使用线程安全函数。 可以在传递给 napi_create_threadsafe_function()napi_finalize 回调中释放与 napi_threadsafe_function 关联的数据。 napi_create_threadsafe_function的参数initial_thread_count表示线程安全函数的初始获取次数,而不是在创建时多次调用napi_acquire_threadsafe_function

一旦使用 napi_threadsafe_function 的线程数达到零,则没有其他线程可以通过调用 napi_acquire_threadsafe_function() 开始使用它。 事实上,除 napi_release_threadsafe_function() 之外的所有后续 API 调用都将返回错误值 napi_closing

线程安全函数可以通过给 napi_release_threadsafe_function() 赋值 napi_tsfn_abort 来实现 "aborted"。 这将导致除 napi_release_threadsafe_function() 之外与线程安全函数关联的所有后续 API 甚至在其引用计数达到零之前就返回 napi_closing。 特别是,napi_call_threadsafe_function() 将返回 napi_closing,从而通知线程不再可能对线程安全函数进行异步调用。 这可以用作终止线程的标准。 napi_call_threadsafe_function() 接收到 napi_closing 的返回值后,线程不得再使用线程安全函数,因为不再保证会分配它。

决定是否保持进程运行#

与 libuv 句柄类似,线程安全函数可以是 "referenced" 和 "unreferenced"。 "referenced" 线程安全函数将导致创建它的线程上的事件循环保持活动状态,直到线程安全函数被销毁。 相反,"unreferenced" 线程安全函数不会阻止事件循环退出。 API napi_ref_threadsafe_functionnapi_unref_threadsafe_function 就是为此目的而存在的。

napi_unref_threadsafe_function 既没有将线程安全函数标记为可以被销毁,也没有 napi_ref_threadsafe_function 阻止它被销毁。

napi_create_threadsafe_function#

NAPI_EXTERN napi_status
napi_create_threadsafe_function(napi_env env,
                                napi_value func,
                                napi_value async_resource,
                                napi_value async_resource_name,
                                size_t max_queue_size,
                                size_t initial_thread_count,
                                void* thread_finalize_data,
                                napi_finalize thread_finalize_cb,
                                void* context,
                                napi_threadsafe_function_call_js call_js_cb,
                                napi_threadsafe_function* result); 
  • [in] env: 调用 API 的环境。
  • [in] func: 从另一个线程调用的可选 JavaScript 函数。 如果 NULL 传递给 call_js_cb,则必须提供它。
  • [in] async_resource: 与将传递给可能的 async_hooks init 钩子 的异步工作关联的可选对象。
  • [in] async_resource_name: 一个 JavaScript 字符串,用于为 async_hooks API 公开的诊断信息提供的资源类型提供标识符。
  • [in] max_queue_size: 队列的最大大小。 0 为无限制。
  • [in] initial_thread_count: 初始获取数,即初始线程数,包括将使用此函数的主线程。
  • [in] thread_finalize_data: 要传递给 thread_finalize_cb 的可选数据。
  • [in] thread_finalize_cb: napi_threadsafe_function 被销毁时调用的可选函数。
  • [in] context: 附加到生成的 napi_threadsafe_function 的可选数据。
  • [in] call_js_cb: 可选回调调用 JavaScript 函数以响应不同线程上的调用。 此回调将在主线程上调用。 如果没有给出,JavaScript 函数将在没有参数的情况下调用,并将 undefined 作为其 this 值。 napi_threadsafe_function_call_js 提供了更多详细信息。
  • [out] result: 异步线程安全的 JavaScript 函数。

napi_get_threadsafe_function_context#

NAPI_EXTERN napi_status
napi_get_threadsafe_function_context(napi_threadsafe_function func,
                                     void** result); 
  • [in] func: 为其检索上下文的线程安全函数。
  • [out] result: 存储上下文的位置。

可以从使用 func 的任何线程调用此 API。

napi_call_threadsafe_function#

NAPI_EXTERN napi_status
napi_call_threadsafe_function(napi_threadsafe_function func,
                              void* data,
                              napi_threadsafe_function_call_mode is_blocking); 
  • [in] func: 要调用的异步线程安全 JavaScript 函数。
  • [in] data: 通过创建线程安全 JavaScript 函数期间提供的回调 call_js_cb 发送到 JavaScript 的数据。
  • [in] is_blocking: 标志,其值可以是 napi_tsfn_blocking,表示如果队列已满,调用应该阻塞;也可以是 napi_tsfn_nonblocking,表示只要队列已满,调用就应该立即返回,状态为 napi_queue_full

不应从 JavaScript 线程使用 napi_tsfn_blocking 调用此 API,因为如果队列已满,可能会导致 JavaScript 线程死锁。

如果从任何线程调用 napi_release_threadsafe_function() 并将 abort 设置为 napi_tsfn_abort,则此 API 将返回 napi_closing。 只有当 API 返回 napi_ok 时,该值才会添加到队列中。

可以从使用 func 的任何线程调用此 API。

napi_acquire_threadsafe_function#

NAPI_EXTERN napi_status
napi_acquire_threadsafe_function(napi_threadsafe_function func); 
  • [in] func: 开始使用异步线程安全的 JavaScript 函数。

线程应在将 func 传递给任何其他线程安全函数 API 以指示它将使用 func 之前调用此 API。 这可以防止 func 在所有其他线程停止使用它时被销毁。

可以从将开始使用 func 的任何线程调用此 API。

napi_release_threadsafe_function#

NAPI_EXTERN napi_status
napi_release_threadsafe_function(napi_threadsafe_function func,
                                 napi_threadsafe_function_release_mode mode); 
  • [in] func: 异步线程安全的 JavaScript 函数,其引用计数将减少。
  • [in] mode: 其值可以是 napi_tsfn_release 的标志,表示当前线程将不再调用线程安全函数,或者是 napi_tsfn_abort,表示除了当前线程之外,没有其他线程应该进一步调用线程安全函数 功能。 如果设置为 napi_tsfn_abort,对 napi_call_threadsafe_function() 的进一步调用将返回 napi_closing,并且不会将更多值放入队列中。

线程停止使用 func 时应调用此 API。 在调用此 API 后将 func 传递给任何线程安全的 API 会产生未定义的结果,因为 func 可能已被销毁。

可以从任何将停止使用 func 的线程调用此 API。

napi_ref_threadsafe_function#

NAPI_EXTERN napi_status
napi_ref_threadsafe_function(napi_env env, napi_threadsafe_function func); 
  • [in] env: 调用 API 的环境。
  • [in] func: 要引用的线程安全函数。

此 API 用于指示在主线程上运行的事件循环在 func 被销毁之前不应退出。 与 uv_ref 类似,它也是幂等的。

napi_unref_threadsafe_function 既没有将线程安全函数标记为可以被销毁,也没有 napi_ref_threadsafe_function 阻止它被销毁。 napi_acquire_threadsafe_functionnapi_release_threadsafe_function 可用于该目的。

此 API 只能从主线程调用。

napi_unref_threadsafe_function#

NAPI_EXTERN napi_status
napi_unref_threadsafe_function(napi_env env, napi_threadsafe_function func); 
  • [in] env: 调用 API 的环境。
  • [in] func: 要取消引用的线程安全函数。

该API用于指示在主线程上运行的事件循环可能会在func被销毁之前退出。 与 uv_unref 类似,它也是幂等的。

此 API 只能从主线程调用。

其他实用工具#

node_api_get_module_file_name#

稳定性: 1 - 实验

NAPI_EXTERN napi_status
node_api_get_module_file_name(napi_env env, const char** result);
 
  • [in] env: 调用 API 的环境。
  • [out] result: 包含加载项加载位置的绝对路径的 URL。 对于本地文件系统上的文件,它将以 file:// 开头。 该字符串以 null 结尾并归 env 所有,因此不得修改或释放。

如果加载项加载过程无法在加载期间建立加载项的文件名,则 result 可能是一个空字符串。