Node-API#

稳定性:2 - 稳定

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

插件的构建/打包方式与标题为 C++ 插件 的章节中概述的方法/工具相同。唯一的区别是原生代码所使用的 API 集合。不再使用 V8 或 Native Abstractions for Node.js API,而是使用 Node-API 中提供的函数。

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

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

使用各种编程语言编写插件#

Node-API 是一个 C API,可确保跨 Node.js 版本和不同编译器级别的 ABI 稳定性。有了这种稳定性保证,就可以在 Node-API 之上使用其他编程语言编写插件。有关更多编程语言和引擎支持的详细信息,请参考语言和引擎绑定

node-addon-api 是官方 C++ 绑定,提供了一种更高效的方式来编写调用 Node-API 的 C++ 代码。此封装器是一个仅包含头文件的库,提供可内联的 C++ API。使用 node-addon-api 构建的二进制文件将依赖于 Node.js 导出的 Node-API 基于 C 的函数的符号。以下代码片段是 node-addon-api 的示例:

Object obj = Object::New(env);
obj["foo"] = String::New(env, "bar");

上述 node-addon-api C++ 代码等效于以下基于 C 的 Node-API 代码:

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++ 编写的,它仍然受益于 C Node-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>
    
  • Node.js 包含并可通过以下方式获得的 libuv API:

    #include <uv.h>
    
  • 通过以下方式获得的 V8 API:

    #include <v8.h>
    

因此,为了使插件在 Node.js 主版本之间保持 ABI 兼容,它必须通过限制自己使用以下内容来专门使用 Node-API:

#include <node_api.h>

并检查其使用的所有外部库,确保该外部库提供类似于 Node-API 的 ABI 稳定性保证。

ABI 稳定性中的枚举值#

Node-API 中定义的所有枚举数据类型都应被视为固定大小的 int32_t 值。位标志枚举类型应有明确的文档记录,它们作为位值与按位或 (|) 等位运算符一起工作。除非另有说明,否则枚举类型应被视为可扩展的。

新的枚举值将被添加到枚举定义的末尾。枚举值不会被删除或重命名。

对于从 Node-API 函数返回或作为 Node-API 函数输出参数提供的枚举类型,该值是一个整数值,插件应处理未知值。新值可以在没有版本防护的情况下引入。例如,在 switch 语句中检查 napi_status 时,插件应包含一个 default 分支,因为较新的 Node.js 版本中可能会引入新的状态码。

对于在输入参数中使用的枚举类型,除非另有说明,否则向 Node-API 函数传递未知整数值的结果是未定义的。新值会添加版本防护,以指示其引入的 Node-API 版本。例如,napi_get_all_property_names 可以扩展 napi_key_filter 的新枚举值。

对于在输入参数和输出参数中都使用的枚举类型,允许在没有版本防护的情况下引入新值。

构建#

与用 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 是一个不错的选择。build_with_cmake 是一个基于 CMake 的原生插件项目示例。

上传预编译二进制文件#

此处列出的三种工具允许原生插件开发者和维护者创建二进制文件并将其上传到公共或私有服务器。这些工具通常与 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 发布。对于使用 CMake.js 的 GitHub 项目,prebuild 是一个不错的选择。

prebuildify#

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

用法#

为了使用 Node-API 函数,请包含位于 node 开发树 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)都将对模块代码可用。

有时会引入影响已发布和稳定 API 的实验性功能。可以通过选择退出(opt-out)来禁用这些功能:

#define NAPI_EXPERIMENTAL
#define NODE_API_EXPERIMENTAL_<FEATURE_NAME>_OPT_OUT
#include <node_api.h>

其中 <FEATURE_NAME> 是一个影响实验性和稳定 API 的实验性功能的名称。

Node-API 版本矩阵#

直到第 9 版,Node-API 版本都是累加的,并且与 Node.js 独立进行版本控制。这意味着任何版本都是对前一个版本的扩展,因为它具有前一个版本的所有 API 以及一些新增功能。每个 Node.js 版本仅支持单个 Node-API 版本。例如 v18.15.0 仅支持 Node-API 版本 8。ABI 稳定性之所以能够实现,是因为 8 是所有以前版本的严格超集。

从第 9 版开始,虽然 Node-API 版本继续独立进行版本控制,但在 Node-API 版本 9 下运行的插件可能需要代码更新才能在 Node-API 版本 10 下运行。ABI 稳定性之所以得以维持,是因为支持高于 8 的 Node-API 版本的 Node.js 版本将支持 8 到其支持的最高版本之间的所有版本,并默认提供 8 版 API,除非插件选择加入更高的 Node-API 版本。这种方法提供了更好地优化现有 Node-API 函数的灵活性,同时保持了 ABI 稳定性。现有插件无需重新编译即可使用较旧的 Node-API 版本继续运行。如果插件需要新 Node-API 版本中的功能,无论如何都需要对现有代码进行更改并重新编译才能使用这些新函数。

在支持 Node-API 版本 9 及更高版本的 Node.js 版本中,定义 NAPI_VERSION=X 并使用现有的插件初始化宏,将插件在运行时要使用的请求的 Node-API 版本嵌入到插件中。如果未设置 NAPI_VERSION,则默认为 8。

此表格在较旧的流中可能不是最新的,最新信息请查看以下位置的最新 API 文档:Node-API 版本矩阵

Node-API 版本 支持于
10 v22.14.0+, 23.6.0+ 以及所有更高版本
9 v18.17.0+, 20.3.0+, 21.0.0 以及所有更高版本
8 v12.22.0+, v14.17.0+, v15.12.0+, 16.0.0 以及所有更高版本
7 v10.23.0+, v12.19.0+, v14.12.0+, 15.0.0 以及所有更高版本
6 v10.20.0+, v12.17.0+, 14.0.0 以及所有更高版本
5 v10.17.0+, v12.11.0+, 13.0.0 以及所有更高版本
4 v10.16.0+, v11.8.0+, 12.0.0 以及所有更高版本
3 v6.14.2*, 8.11.2+, v9.11.0+*, 10.0.0 以及所有更高版本
2 v8.10.0+*, v9.3.0+*, 10.0.0 以及所有更高版本
1 v8.6.0+**, v9.0.0+*, 10.0.0 以及所有更高版本

* Node-API 为实验性。

** Node.js 8.0.0 将 Node-API 作为实验性功能包含在内。它作为 Node-API 版本 1 发布,但一直演变到 Node.js 8.6.0。Node.js 8.6.0 之前的版本中的 API 有所不同。我们推荐使用 Node-API 版本 3 或更高版本。

为 Node-API 记录的每个 API 都会有一个名为 added in: 的标题,而稳定的 API 将会有额外的 Node-API version: 标题。当使用支持 Node-API version: 中显示的版本或更高版本的 Node.js 版本时,API 可以直接使用。当使用不支持所列 Node-API version: 的 Node.js 版本,或者没有列出 Node-API version: 时,只有在 #define NAPI_EXPERIMENTAL 预先包含 node_api.hjs_native_api.h 的情况下,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.js 的 Node-API 实现或 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 NODE_API_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 an exception is already pending, don't rethrow it */  \
      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;
  NODE_API_CALL(env, napi_create_object(env, &result));

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

  NODE_API_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(/* napi_env env, napi_value exports */) {
  // 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 语言规范代理 (Agents) 章节将“代理”定义为一个自包含的环境,JavaScript 代码在该环境中运行。进程可能会并发或顺序地启动和终止多个此类代理。

Node.js 环境对应于一个 ECMAScript 代理。在主进程中,环境在启动时创建,并且可以在单独的线程上创建其他环境以充当 工作线程 (worker threads)。当 Node.js 被嵌入到另一个应用程序中时,应用程序的主线程也可能在应用程序进程的生命周期内多次构造和销毁 Node.js 环境,使得应用程序创建的每个 Node.js 环境在其生命周期内都可以依次创建和销毁其他环境作为工作线程。

从原生插件的角度来看,这意味着它提供的绑定可能会被多次调用,来自多个上下文,甚至可以从多个线程并发调用。

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

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

napi_set_instance_data#

napi_status napi_set_instance_data(node_api_basic_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(node_api_basic_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_cannot_run_js
} 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:包含与 VM 无关的错误描述的 UTF8 编码字符串。
  • 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 的回调发送。

node_api_basic_env#

稳定性:1 - 实验性

napi_env 变体传递给同步终结器 (node_api_basic_finalize)。有一部分 Node-API 接受类型为 node_api_basic_env 的参数作为其第一个参数。这些 API 不会访问 JavaScript 引擎的状态,因此可以安全地从同步终结器中调用。允许将类型为 napi_env 的参数传递给这些 API;但是,不允许将类型为 node_api_basic_env 的参数传递给访问 JavaScript 引擎状态的 API。在插件使用会导致在传递不正确的指针类型给函数时发出警告和/或错误的标志进行编译时,尝试在不进行强制类型转换的情况下执行此操作会产生编译器警告或错误。从同步终结器中调用此类 API 最终将导致应用程序终止。

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 值是在句柄范围 (handle scope) 的上下文中创建的。当从 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 对象或 外部 (externals) 可以通过它进行“标记”,以确保它们属于某种特定类型。这比 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 内部创建句柄和/或回调范围。

node_api_basic_finalize#

稳定性:1 - 实验性

插件提供的函数指针类型,允许用户在外部拥有的数据准备好被清理时(因为关联它的对象已被垃圾回收)收到通知。用户必须提供满足以下签名的函数,该函数将在对象被回收时调用。目前,node_api_basic_finalize 可用于找出具有外部数据的对象何时被回收。

typedef void (*node_api_basic_finalize)(node_api_basic_env env,
                                      void* finalize_data,
                                      void* finalize_hint);

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

由于这些函数可能在 JavaScript 引擎处于无法执行 JavaScript 代码的状态时被调用,因此只能调用将 node_api_basic_env 作为其第一个参数的 Node-API。node_api_post_finalizer 可用于调度需要在当前垃圾回收周期完成后访问 JavaScript 引擎状态的 Node-API 调用。

node_api_create_external_string_latin1node_api_create_external_string_utf16 的情况下,env 参数可以为 null,因为外部字符串可以在环境关闭的后半部分被回收。

变更历史

  • 实验性 (NAPI_EXPERIMENTAL)

    仅能调用将 node_api_basic_env 作为其第一个参数的 Node-API,否则应用程序将以适当的错误消息终止。此功能可以通过定义 NODE_API_EXPERIMENTAL_BASIC_ENV_OPT_OUT 关闭。

napi_finalize#

插件提供的函数指针类型,允许用户在垃圾回收周期完成后,响应垃圾回收事件调度一组对 Node-API 的调用。这些函数指针可以与 node_api_post_finalizer 一起使用。

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

变更历史

  • 实验性 (定义了 NAPI_EXPERIMENTAL)

    此类型的函数不再能用作终结器,除非与 node_api_post_finalizer 一起使用。必须改用 node_api_basic_finalize。此功能可以通过定义 NODE_API_EXPERIMENTAL_BASIC_ENV_OPT_OUT 关闭。

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 调用 JavaScript 函数就足够了,而不是通过 napi_make_callback

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

typedef void (*napi_threadsafe_function_call_js)(napi_env env,
                                                 napi_value js_callback,
                                                 void* context,
                                                 void* data);
  • [in] env:用于 API 调用的环境,如果正在销毁线程安全函数并且可能需要释放 data,则为 NULL
  • [in] js_callback:要调用的 JavaScript 函数,如果正在销毁线程安全函数并且可能需要释放 data,则为 NULL。如果线程安全函数是在没有 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_status 可能值集合定义在 napi_api_types.h 中。

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:上一个错误的 Node-API 状态码。

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

不要依赖任何扩展信息的内容或格式,因为它不受语义版本控制 (SemVer) 约束,并且可能随时更改。它仅供记录目的使用。

napi_get_last_error_info#
napi_status
napi_get_last_error_info(node_api_basic_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,在 JavaScript 中可以处理异常。

第二种方法是尝试处理异常。在某些情况下,原生代码可以捕获异常,采取适当的操作,然后继续。这仅建议在明确知道可以安全处理异常的特定情况下使用。在这些情况下,可以使用 napi_get_and_clear_last_exception 来获取并清除异常。如果成功,result 将包含指向最后抛出的 JavaScript Object 的句柄。如果获取异常后确定无法处理该异常,可以使用 napi_throw 重新抛出它,其中 error 是要抛出的 JavaScript 值。

如果原生代码需要抛出异常或确定 napi_value 是否是 JavaScript Error 对象的实例,也可以使用以下工具函数:napi_throw_error, napi_throw_type_error, napi_throw_range_error, node_api_throw_syntax_errornapi_is_error

如果原生代码需要创建 Error 对象,也可以使用以下工具函数:napi_create_error, napi_create_type_error, napi_create_range_errornode_api_create_syntax_error,其中 result 是指向新创建的 JavaScript Error 对象的 napi_value

Node.js 项目正在为内部产生的所有错误添加错误代码。目标是让应用程序使用这些错误代码进行所有错误检查。关联的错误消息将保留,但仅用于记录和显示,并预期该消息可能会在不应用 SemVer 的情况下更改。为了在 Node-API 中支持此模型(在内部功能和模块特定功能中,这是一种好的做法),throw_create_ 函数接受一个可选的 code 参数,该参数是添加到错误对象的代码字符串。如果可选参数为 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#
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:引用要用作 Error 消息的 JavaScript stringnapi_value
  • [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:引用要用作 Error 消息的 JavaScript stringnapi_value
  • [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:引用要用作 Error 消息的 JavaScript stringnapi_value
  • [out] result:表示所创建错误的 napi_value

如果 API 调用成功,则返回 napi_ok

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

node_api_create_syntax_error#
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:引用要用作 Error 消息的 JavaScript stringnapi_value
  • [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 返回。这些句柄必须保持对象“存活”,直到原生代码不再需要它们,否则对象在原生代码完成使用之前可能会被回收。

当返回对象句柄时,它们与一个“范围 (scope)”关联。默认范围的生命周期与原生方法调用的生命周期相关联。结果是,默认情况下,句柄保持有效,并且与这些句柄关联的对象将在原生方法调用的生命周期内保持存活。

然而,在许多情况下,句柄需要保持有效的时间比原生方法的生命周期短或长。以下章节描述了可用于从默认值更改句柄生命周期的 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 提供了建立新“范围”的能力,新创建的句柄将与该范围关联。一旦不再需要这些句柄,范围就可以被“关闭”,并且与该范围关联的任何句柄都将失效。用于打开/关闭范围的方法是 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 支持“可转义范围”。可转义范围允许一个句柄被“提升”,以便它“逃离 (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:表示要逃离的 JavaScript Objectnapi_value
  • [out] result:表示外部范围中逃离 Object 的句柄的 napi_value

如果 API 调用成功,则返回 napi_ok

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

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

生命周期长于原生方法的数值引用#

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

Node-API 提供了创建值的持久引用的方法。目前 Node-API 仅允许为一组有限的值类型创建引用,包括对象、外部、函数和符号。

每个引用都有一个关联的计数,值为 0 或更高,这决定了引用是否会保持对应的值存活。计数为 0 的引用不会阻止值被回收。对象(对象、函数、外部)和符号类型的值将成为“弱”引用,在它们未被回收时仍然可以访问。任何大于 0 的计数都将阻止值被回收。

符号值有不同的形式。真正的弱引用语义仅由使用 napi_create_symbol 函数或 JavaScript Symbol() 构造函数调用创建的本地符号支持。使用 node_api_symbol_for 函数或 JavaScript Symbol.for() 函数调用创建的全局注册符号始终保持强引用,因为垃圾回收器不会收集它们。知名的符号(如 Symbol.iterator)也是如此。它们也永远不会被垃圾回收器收集。

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

插件不再需要引用时必须将其删除。当引用被删除时,它将不再阻止对应的对象被回收。未能删除持久引用会导致“内存泄漏”,持久引用的原生内存和堆上的对应对象都将被永久保留。

可以创建引用同一对象的多个持久引用,每个引用将根据其各自的计数来决定是否保持对象存活。对同一对象的多个持久引用可能会导致意外地保持原生内存存活。持久引用的原生结构必须保持存活,直到被引用对象的终结器执行为止。如果为同一对象创建了新的持久引用,该对象的终结器将不会运行,并且较早的持久引用所指向的原生内存将不会被释放。如果可能,这可以通过调用 napi_delete_reference 以及 napi_reference_unref 来避免。

变更历史

  • 第 10 版 (NAPI_VERSION 定义为 10 或更高)

    可以为所有值类型创建引用。新的受支持值类型不支持弱引用语义,并且当引用计数变为 0 时,这些类型的值会被释放,并且无法再从该引用访问。

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 创建一个具有指定的引用计数且指向传入值的指向新引用。

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_ref 关联的 JavaScript 值的 napi_value。否则,result 将为 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(node_api_basic_env env,
                                                  napi_cleanup_hook fun,
                                                  void* arg);

fun 注册为一个函数,在当前 Node.js 环境退出时使用 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(node_api_basic_env env,
                                                     void (*fun)(void* arg),
                                                     void* arg);

注销 fun 作为在当前 Node.js 环境退出时使用 arg 参数运行的函数。参数和函数值都必须完全匹配。

该函数必须最初是通过 napi_add_env_cleanup_hook 注册的,否则进程将终止。

napi_add_async_cleanup_hook#
NAPI_EXTERN napi_status napi_add_async_cleanup_hook(
    node_api_basic_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 不同,该钩子允许是异步的。

否则,其行为通常与 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 回调中出现释放后使用 (use-after-free) 的情况,插件应该使用 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_env env, napi_value exports */) {
  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;
}

参数 envexports 被提供给 NAPI_MODULE_INIT 宏的主体。

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

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

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

有关构建插件模块的通用详细信息,请参考现有 API。

使用 JavaScript 值#

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

从根本上讲,这些 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;

属性过滤器位标志。这与位运算符一起工作以构建复合过滤器。

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 语言规范的 语言类型部分 中描述的类型。除了该部分中的类型外,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_float16_array,
} napi_typedarray_type;

这表示 TypedArray 底层的二进制标量数据类型。此枚举的元素对应于 ECMAScript 语言规范TypedArray 对象部分

对象创建函数#

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 语言规范的 Array 对象部分 中有描述。

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 的长度属性被设置为传入的 length 参数。但是,不保证虚拟机在创建数组时会预先分配底层缓冲区。该行为留给底层的虚拟机实现。如果缓冲区必须是可以通过 C 直接读写的连续内存块,请考虑使用 napi_create_external_arraybuffer

JavaScript 数组在 ECMAScript 语言规范的 Array 对象部分 中有描述。

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 底层字节缓冲区的指针。可以通过传入 NULL 来选择性地忽略 data
  • [out] result: 表示 JavaScript ArrayBuffernapi_value

如果 API 调用成功,则返回 napi_ok

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

JavaScript ArrayBuffer 对象在 ECMAScript 语言规范的 ArrayBuffer 对象部分 中有描述。

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: 指向底层缓冲区的原始指针。可以通过传入 NULL 来选择性地忽略 data
  • [out] result: 表示 node::Buffernapi_value

如果 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 底层数据缓冲区的指针。可以通过传入 NULL 来选择性地忽略 result_data
  • [out] result: 表示 node::Buffernapi_value

如果 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 语言规范的 Date 对象部分 中有描述。

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 就是这样一个运行时,如该问题 electron/issues/35801 所述。

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

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

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

JavaScript ArrayBuffer 对象在 ECMAScript 语言规范的 ArrayBuffer 对象部分 中有描述。

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: 表示 node::Buffernapi_value

如果 API 调用成功,则返回 napi_ok

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

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

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

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

对于 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 语言规范的 对象类型部分 中有描述。

node_api_create_object_with_properties#

稳定性:1 - 实验性

napi_status node_api_create_object_with_properties(napi_env env,
                                                   napi_value prototype_or_null,
                                                   const napi_value* property_names,
                                                   const napi_value* property_values,
                                                   size_t property_count,
                                                   napi_value* result)
  • [in] env:调用 API 的环境。
  • [in] prototype_or_null: 新对象的原型对象。可以是表示要用作原型的 JavaScript 对象的 napi_value、表示 JavaScript nullnapi_value,或将转换为 nullnullptr
  • [in] property_names: 表示属性名称的 napi_value 数组。
  • [in] property_values: 表示属性值的 napi_value 数组。
  • [in] property_count: 数组中的属性数量。
  • [out] result: 表示 JavaScript Objectnapi_value

如果 API 调用成功,则返回 napi_ok

此 API 创建一个具有指定原型和属性的 JavaScript Object。这比调用 napi_create_object 后跟多个 napi_set_property 调用更高效,因为它可以在创建对象时原子地包含所有属性,从而避免潜在的 V8 映射转换。

数组 property_namesproperty_values 必须具有由 property_count 指定的相同长度。属性按它们在数组中出现的顺序添加到对象中。

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

如果 API 调用成功,则返回 napi_ok

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

JavaScript symbol 类型在 ECMAScript 语言规范的 symbol 类型部分 中有描述。

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

如果 API 调用成功,则返回 napi_ok

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

JavaScript symbol 类型在 ECMAScript 语言规范的 symbol 类型部分 中有描述。

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 对象提供了一个底层数据缓冲区的类似数组的视图,其中每个元素具有相同的底层二进制标量数据类型。

要求 (length * size_of_element) + byte_offset 必须 <= 传入数组的字节大小。如果不是,则会引发 RangeError 异常。

JavaScript TypedArray 对象在 ECMAScript 语言规范的 TypedArray 对象部分 中有描述。

node_api_create_buffer_from_arraybuffer#
napi_status NAPI_CDECL node_api_create_buffer_from_arraybuffer(napi_env env,
                                                              napi_value arraybuffer,
                                                              size_t byte_offset,
                                                              size_t byte_length,
                                                              napi_value* result)
  • [in] env: API 执行的环境。
  • [in] arraybuffer: 将从中创建 buffer 的 ArrayBuffer
  • [in] byte_offset: ArrayBuffer 中开始创建 buffer 的字节偏移量。
  • [in] byte_length: 从 ArrayBuffer 创建的 buffer 的字节长度。
  • [out] result: 表示创建的 JavaScript Buffer 对象的 napi_value

如果 API 调用成功,则返回 napi_ok

此 API 从现有的 ArrayBuffer 创建 JavaScript Buffer 对象。Buffer 对象是 Node.js 特有的类,提供了在 JavaScript 中直接处理二进制数据的方法。

字节范围 [byte_offset, byte_offset + byte_length) 必须在 ArrayBuffer 的范围内。如果 byte_offset + byte_length 超过了 ArrayBuffer 的大小,则会引发 RangeError 异常。

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: DataView 底层的 ArrayBufferSharedArrayBuffer
  • [in] byte_offset: ArrayBuffer 中开始投影 DataView 的字节偏移量。
  • [out] result: 表示 JavaScript DataViewnapi_value

如果 API 调用成功,则返回 napi_ok

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

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

JavaScript DataView 对象在 ECMAScript 语言规范的 DataView 对象部分 中有描述。

从 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 语言规范的 数字类型部分 中有描述。

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 语言规范的 数字类型部分 中有描述。

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 语言规范的 数字类型部分 中有描述。请注意,int64_t 的全部范围无法以完全精度在 JavaScript 中表示。超出 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 语言规范的 数字类型部分 中有描述。

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 小端序 64 位字的数组。
  • [out] result: 表示 JavaScript BigIntnapi_value

如果 API 调用成功,则返回 napi_ok

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

结果 BigInt 计算为:(–1)sign_bit (words[0] × (264)0 + words[1] × (264)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 语言规范的 字符串类型部分 中有描述。

node_api_create_external_string_latin1#
napi_status
node_api_create_external_string_latin1(napi_env env,
                                       char* str,
                                       size_t length,
                                       napi_finalize finalize_callback,
                                       void* finalize_hint,
                                       napi_value* result,
                                       bool* copied);
  • [in] env:调用 API 的环境。
  • [in] str: 表示 ISO-8859-1 编码字符串的字符缓冲区。
  • [in] length: 字符串的字节长度,如果以 null 结尾,则为 NAPI_AUTO_LENGTH
  • [in] finalize_callback: 字符串被回收时调用的函数。该函数将使用以下参数调用
  • [in] env: 插件运行的环境。如果字符串作为 worker 或主 Node.js 实例终止的一部分被回收,此值可能为 null。
  • [in] data: 这是作为 void* 指针的 str 值。
  • [in] finalize_hint: 这是提供给 API 的 finalize_hint 值。napi_finalize 提供了更多详细信息。此参数是可选的。传递 null 值意味着插件不需要在对应的 JavaScript 字符串被回收时得到通知。
  • [in] finalize_hint:收集期间传递给终结回调的可选提示。
  • [out] result: 表示 JavaScript stringnapi_value
  • [out] copied: 字符串是否被复制。如果是,终结器将已经被调用以销毁 str

    如果 API 调用成功,则返回 napi_ok

    此 API 从 ISO-8859-1 编码的 C 字符串创建一个 JavaScript string 值。原生字符串可能不会被复制,因此必须在 JavaScript 值的整个生命周期内保持存在。

    JavaScript string 类型在 ECMAScript 语言规范的 字符串类型部分 中有描述。

  • 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 语言规范的 字符串类型部分 中有描述。

    node_api_create_external_string_utf16#
    napi_status
    node_api_create_external_string_utf16(napi_env env,
                                          char16_t* str,
                                          size_t length,
                                          napi_finalize finalize_callback,
                                          void* finalize_hint,
                                          napi_value* result,
                                          bool* copied);
    
    • [in] env:调用 API 的环境。
    • [in] str: 表示 UTF16-LE 编码字符串的字符缓冲区。
    • [in] length: 字符串的双字节码单元长度,如果以 null 结尾,则为 NAPI_AUTO_LENGTH
    • [in] finalize_callback: 字符串被回收时调用的函数。该函数将使用以下参数调用
    • [in] env: 插件运行的环境。如果字符串作为 worker 或主 Node.js 实例终止的一部分被回收,此值可能为 null。
    • [in] data: 这是作为 void* 指针的 str 值。
    • [in] finalize_hint: 这是提供给 API 的 finalize_hint 值。napi_finalize 提供了更多详细信息。此参数是可选的。传递 null 值意味着插件不需要在对应的 JavaScript 字符串被回收时得到通知。
  • [in] finalize_hint:收集期间传递给终结回调的可选提示。
  • [out] result: 表示 JavaScript stringnapi_value
  • [out] copied: 字符串是否被复制。如果是,终结器将已经被调用以销毁 str

    如果 API 调用成功,则返回 napi_ok

    此 API 从 UTF16-LE 编码的 C 字符串创建一个 JavaScript string 值。原生字符串可能不会被复制,因此必须在 JavaScript 值的整个生命周期内保持存在。

    JavaScript string 类型在 ECMAScript 语言规范的 字符串类型部分 中有描述。

  • 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 语言规范的 字符串类型部分 中有描述。

    用于创建优化属性键的函数#

    许多 JavaScript 引擎(包括 V8)使用内部化的字符串作为键来设置和获取属性值。它们通常使用哈希表来创建和查找此类字符串。虽然这增加了每个键创建的成本,但它通过实现字符串指针的比较而不是整个字符串的比较,提高了之后的操作性能。

    如果打算将新的 JavaScript 字符串用作属性键,那么对于某些 JavaScript 引擎,使用本节中的函数会更高效。否则,请使用 napi_create_string_utf8node_api_create_external_string_utf8 系列函数,因为使用属性键创建方法可能会产生额外的字符串创建/存储开销。

    node_api_create_property_key_latin1#
    napi_status NAPI_CDECL node_api_create_property_key_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 值,用作对象的属性键。原生字符串会被复制。与 napi_create_string_latin1 相比,后续使用相同 str 指针调用此函数可能会受益于请求的 napi_value 的创建加速(取决于引擎)。

    JavaScript string 类型在 ECMAScript 语言规范的 字符串类型部分 中有描述。

    node_api_create_property_key_utf16#
    napi_status NAPI_CDECL node_api_create_property_key_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 语言规范的 字符串类型部分 中有描述。

    node_api_create_property_key_utf8#
    napi_status NAPI_CDECL node_api_create_property_key_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 语言规范的 字符串类型部分 中有描述。

    从 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: 表示要查询长度的 JavaScript Arraynapi_value
    • [out] result: 表示数组长度的 uint32

    如果 API 调用成功,则返回 napi_ok

    此 API 返回数组的长度。

    Array 长度在 ECMAScript 语言规范的 Array 实例长度部分 中有描述。

    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: 表示正在查询的 ArrayBufferSharedArrayBuffernapi_value
    • [out] data: ArrayBufferSharedArrayBuffer 的底层数据缓冲区如果为 0,这可能为 NULL 或任何其他指针值。
    • [out] byte_length: 底层数据缓冲区的字节长度。

    如果 API 调用成功,则返回 napi_ok

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

    警告: 使用此 API 时要小心。即使在返回之后,底层数据缓冲区的生命周期也由 ArrayBufferSharedArrayBuffer 管理。使用此 API 的一种可能安全的方法是结合使用 napi_create_reference,这可以用来保证对 ArrayBufferSharedArrayBuffer 生命周期的控制。在同一个回调中使用返回的数据缓冲区也是安全的,只要没有调用其他可能触发垃圾回收的 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: 表示正在查询的 node::BufferUint8Arraynapi_value
    • [out] data: node::BufferUint8Array 的底层数据缓冲区。如果长度为 0,这可能为 NULL 或任何其他指针值。
    • [out] length: 底层数据缓冲区的字节长度。

    如果 API 调用成功,则返回 napi_ok

    此方法返回与 napi_get_typedarray_info 相同的 databyte_length。而且 napi_get_typedarray_info 也接受 node::Buffer(即 Uint8Array)作为值。

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

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

    napi_get_prototype#
    napi_status napi_get_prototype(napi_env env,
                                   napi_value object,
                                   napi_value* result)
    
    • [in] env:调用 API 的环境。
    • [in] object: 表示要返回其原型的 JavaScript Objectnapi_value。这返回等同于 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: 表示要查询属性的 TypedArraynapi_value
    • [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 时要小心,因为底层数据缓冲区由虚拟机管理。

    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: 表示要查询属性的 DataViewnapi_value
    • [out] byte_length: DataView 中的字节数。
    • [out] data: DataView 底层的数据缓冲区。如果 byte_length 为 0,这可能为 NULL 或任何其他指针值。
    • [out] arraybuffer: DataView 底层的 ArrayBuffer
    • [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: 表示 JavaScript Datenapi_value
    • [out] result: 作为 double 的时间值,表示自 1970 年 1 月 1 日 UTC 午夜以来的毫秒数。

    此 API 不观察闰秒;它们会被忽略,因为 ECMAScript 与 POSIX 时间规范保持一致。

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

    此 API 返回给定 JavaScript Date 的时间值的 C double 原始类型。

    napi_get_value_bool#
    napi_status napi_get_value_bool(napi_env env, napi_value value, bool* result)
    
    • [in] env:调用 API 的环境。
    • [in] value: 表示 JavaScript Booleannapi_value
    • [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: 表示 JavaScript numbernapi_value
    • [out] result: 给定 JavaScript number 的 C double 原始等效值。

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

    此 API 返回给定 JavaScript number 的 C double 原始等效值。

    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: 表示 JavaScript BigIntnapi_value
    • [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: 表示 JavaScript BigIntnapi_value
    • [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: 表示 JavaScript BigIntnapi_value
    • [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: 表示 JavaScript 外部值的 napi_value
    • [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: 表示 JavaScript numbernapi_value
    • [out] result: 给定 JavaScript number 的 C int32 原始等效值。

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

    此 API 返回给定 JavaScript number 的 C int32 原始等效值。

    如果数字超过 32 位整数的范围,则结果将被截断为相当于底部 32 位的值。如果值 > 231 - 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: 表示 JavaScript numbernapi_value
    • [out] result: 给定 JavaScript number 的 C int64 原始等效值。

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

    此 API 返回给定 JavaScript number 的 C int64 原始等效值。

    超出 Number.MIN_SAFE_INTEGER -(2**53 - 1) - Number.MAX_SAFE_INTEGER (2**53 - 1) 范围的 number 值将丢失精度。

    非有限数字值(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: 表示 JavaScript 字符串的 napi_value
    • [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: 表示 JavaScript 字符串的 napi_value
    • [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: 表示 JavaScript 字符串的 napi_value
    • [in] buf: 写入 UTF16-LE 编码字符串的缓冲区。如果传入 NULL,则返回字符串的双字节码单元长度(不包括空终止符)。
    • [in] bufsize: 目标缓冲区的大小。当此值不足时,返回的字符串会被截断并以 null 结尾。如果此值为零,则不返回字符串,且不对缓冲区进行任何更改。
    • [out] result: 复制到缓冲区中的双字节码单元数,不包括空终止符。

    如果 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: 表示 JavaScript numbernapi_value
    • [out] result: 给定 napi_value 作为 uint32_t 的 C 原始等效值。

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

    此 API 返回给定 napi_value 作为 uint32_t 的 C 原始等效值。

    获取全局实例的函数#

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

    如果 API 调用成功,则返回 napi_ok

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

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

    如果 API 调用成功,则返回 napi_ok

    此 API 返回 global 对象。

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

    如果 API 调用成功,则返回 napi_ok

    此 API 返回 null 对象。

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

    如果 API 调用成功,则返回 napi_ok

    此 API 返回 Undefined 对象。

    使用 JavaScript 值和抽象操作#

    Node-API 公开了一组 API 来对 JavaScript 值执行一些抽象操作。

    这些 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: 表示强制转换后的 JavaScript Booleannapi_value

    如果 API 调用成功,则返回 napi_ok

    此 API 实现了在 ECMAScript 语言规范的 ToBoolean 部分 中定义的抽象操作 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: 表示强制转换后的 JavaScript numbernapi_value

    如果 API 调用成功,则返回 napi_ok

    此 API 实现了在 ECMAScript 语言规范的 ToNumber 部分 中定义的抽象操作 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: 表示强制转换后的 JavaScript Objectnapi_value

    如果 API 调用成功,则返回 napi_ok

    此 API 实现了在 ECMAScript 语言规范的 ToObject 部分 中定义的抽象操作 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: 表示强制转换后的 JavaScript stringnapi_value

    如果 API 调用成功,则返回 napi_ok

    此 API 实现了在 ECMAScript 语言规范的 ToString 部分 中定义的抽象操作 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 表示行为类似于在对象上调用 typeof 运算符,如 ECMAScript 语言规范的 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 表示在对象上调用 instanceof 运算符,如 ECMAScript 语言规范的 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 语言规范的 IsArray 部分 中所定义。

    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::BufferUint8Array 对象。

    如果 API 调用成功,则返回 napi_ok

    此 API 检查传入的 Object 是否为 buffer 或 Uint8Array。如果调用者需要检查该值是否为 Uint8Array,则应首选 napi_is_typedarray

    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 语言规范的 IsStrctEqual 部分 中所定义。

    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 语言规范的 detachArrayBuffer 部分 中所定义。

    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,则认为它已分离。

    此 API 表示对 ArrayBuffer IsDetachedBuffer 操作的调用,如 ECMAScript 语言规范的 isDetachedBuffer 部分 中所定义。

    node_api_is_sharedarraybuffer#

    稳定性:1 - 实验性

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

    如果 API 调用成功,则返回 napi_ok

    此 API 检查传入的 Object 是否为 SharedArrayBuffer

    node_api_create_sharedarraybuffer#

    稳定性:1 - 实验性

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

    如果 API 调用成功,则返回 napi_ok

    此 API 返回对应于 JavaScript SharedArrayBuffer 的 Node-API 值。SharedArrayBuffer 用于表示可以在多个工作线程之间共享的固定长度二进制数据缓冲区。

    分配的 SharedArrayBuffer 将拥有一个底层字节缓冲区,其大小由传入的 byte_length 参数决定。如果调用者想要直接操作缓冲区,底层缓冲区会选择性地返回给调用者。该缓冲区只能从原生代码直接写入。要从 JavaScript 写入此缓冲区,需要创建一个类型化数组或 DataView 对象。

    JavaScript SharedArrayBuffer 对象在 ECMAScript 语言规范的 SharedArrayBuffer 对象部分 中有描述。

    使用 JavaScript 属性#

    Node-API 公开了一组 API 来获取和设置 JavaScript 对象上的属性。

    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 语言规范属性特性部分 中列出的特性。它们可以是以下一个或多个位标志

    • napi_default:没有在属性上设置明确的属性。默认情况下,属性是只读的、不可枚举且不可配置的。
    • napi_writable:属性是可写的。
    • napi_enumerable:属性是可枚举的。
    • napi_configurable:属性是可配置的,如 ECMAScript 语言规范的 属性特性部分 中所定义。
    • 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 字符串或 symbol。属性必须提供 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 的可枚举属性名称。键为 Symbol 的 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:属性删除是否成功。通过传入 NULL 可以选择忽略 result

    如果 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

    此方法等效于调用 napi_set_property,并使用由传入 utf8Name 的字符串创建的 napi_value

    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

    此方法等效于调用 napi_get_property,并使用由传入 utf8Name 的字符串创建的 napi_value

    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

    此方法等效于调用 napi_has_property,并使用由传入 utf8Name 的字符串创建的 napi_value

    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

    此 API 返回传入的 Object 是否在请求索引处具有元素。

    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:元素删除是否成功。通过传入 NULL 可以选择忽略 result

    如果 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_countproperties 数组中的元素数量。
    • [in] properties:属性描述符数组。

    如果 API 调用成功,则返回 napi_ok

    此方法允许高效地定义给定对象上的多个属性。这些属性使用属性描述符(参见 napi_property_descriptor)进行定义。给定此类属性描述符的数组,此 API 将按照 ECMA-262 规范的 DefineOwnProperty 部分 中定义的 DefineOwnProperty() 方法,逐个设置对象上的属性。

    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 部分 中有描述。

    node_api_set_prototype#

    稳定性:1 - 实验性

    napi_status node_api_set_prototype(napi_env env,
                                       napi_value object,
                                       napi_value value);
    
    • [in] env:调用 Node-API 的环境。
    • [in] object:要在其上设置原型的对象。
    • [in] value:原型值。

    如果 API 调用成功,则返回 napi_ok

    此 API 设置传入的 Object 的原型。

    使用 JavaScript 函数#

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

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

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

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

    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:表示要调用的 JavaScript 函数的 napi_value
    • [in] argcargv 数组中的元素数量。
    • [in] argvnapi_values 数组,表示作为参数传递给该函数的 JavaScript 值。
    • [out] result:表示返回的 JavaScript 对象的 napi_value

    如果 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] lengthutf8name 的字节长度,如果是以 null 结尾的,则为 NAPI_AUTO_LENGTH
    • [in] cb:当调用此函数对象时应调用的原生函数。napi_callback 提供了更多详细信息。
    • [in] data:用户提供的数据上下文。当稍后调用该函数时,此数据将被传回。
    • [out] result:表示新创建函数的 JavaScript 函数对象的 napi_value

    如果 API 调用成功,则返回 napi_ok

    此 API 允许插件作者在原生代码中创建函数对象。这是允许 JavaScript 回调插件原生代码的主要机制。

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

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

    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 语言规范的 Function 对象部分 中有描述。

    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 数组的长度,并接收实际的参数数量。通过传入 NULL 可以选择忽略 argc
    • [out] argv:C 数组的 napi_value,参数将被复制到其中。如果参数多于提供的数量,则仅复制请求数量的参数。如果提供的参数少于声称的数量,则 argv 的其余部分填充为表示 undefinednapi_value。通过传入 NULL 可以选择忽略 argv
    • [out] thisArg:接收调用的 JavaScript this 参数。通过传入 NULL 可以选择忽略 thisArg
    • [out] data:接收回调的数据指针。通过传入 NULL 可以选择忽略 data

    如果 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:表示要作为构造函数调用的 JavaScript 函数的 napi_value
    • [in] argcargv 数组中的元素数量。
    • [in] argv:作为 napi_value 的 JavaScript 值数组,表示构造函数的参数。如果 argc 为零,则可以通过传入 NULL 来省略此参数。
    • [out] result:表示返回的 JavaScript 对象的 napi_value,在本例中是构造出来的对象。

    此方法用于使用给定的表示对象构造函数的 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

    对象包装(Object wrap)#

    Node-API 提供了一种“包装”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 提供了类型标记功能。

    类型标记(Type tag)是一个对于插件唯一的 128 位整数。Node-API 提供 napi_type_tag 结构来存储类型标记。当此值与存储在 napi_value 中的 JavaScript 对象或 external 一起传递给 napi_type_tag_object() 时,该 JavaScript 对象将被“标记”上该类型标记。此“标记”在 JavaScript 端是不可见的。当 JavaScript 对象到达原生绑定时,可以使用 napi_check_object_type_tag() 和原始类型标记来确定该 JavaScript 对象之前是否被该类型标记“标记”过。这创建了一种比 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] lengthutf8name 的字节长度,如果是以 null 结尾的,则为 NAPI_AUTO_LENGTH
    • [in] constructor:处理构造类实例的回调函数。包装 C++ 类时,此方法必须是具有 napi_callback 签名的静态成员。不能使用 C++ 类构造函数。napi_callback 提供了更多详细信息。
    • [in] data:可选数据,将作为回调信息中的 data 属性传递给构造函数回调。
    • [in] property_countproperties 数组参数中的项数。
    • [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++ 类实例后,可以使用 napi_unwrap,从没有 napi_static 属性的属性描述符中给出的静态函数中调用 C++ 类的非静态数据属性、访问器和方法。

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

    napi_define_class 返回的 JavaScript 构造函数通常会被保存并稍后用于从原生代码构造该类的新实例,和/或检查提供的值是否为该类的实例。在这种情况下,为了防止函数值被垃圾回收,可以使用 napi_create_reference 创建一个对其的强持久引用,确保引用计数保持 >= 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(),将新构造的实例包装在作为构造函数回调的 this 参数的已创建的 JavaScript 对象中。(该 this 对象是从构造函数的 prototype 创建的,因此它已经具有所有实例属性和方法的定义。)

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

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

    注意:可选返回的引用(如果已获取)只能通过 napi_delete_reference 删除,以响应终结回调的调用。如果在此之前删除它,则终结回调可能永远不会被调用。因此,在获取引用时,还需要终结回调,以便实现对该引用的正确处置。

    终结回调可能会被延迟,留下一个对象已被垃圾回收(且弱引用无效)但终结器尚未被调用的时间窗口。当在 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 中的原生实例并移除包装。如果终结回调与该包装相关联,则当 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 对象或 external
    • [in] type_tag:要用于标记对象的标签。

    如果 API 调用成功,则返回 napi_ok

    type_tag 指针的值与 JavaScript 对象或 external 相关联。然后可以使用 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 对象或 external
    • [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,
                                   node_api_basic_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 对象被垃圾回收时,该回调将被调用。

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

    注意:可选返回的引用(如果已获取)只能通过 napi_delete_reference 删除,以响应终结回调的调用。如果在此之前删除它,则终结回调可能永远不会被调用。因此,在获取引用时,还需要终结回调,以便实现对该引用的正确处置。

    node_api_post_finalizer#

    稳定性:1 - 实验性

    napi_status node_api_post_finalizer(node_api_basic_env env,
                                        napi_finalize finalize_cb,
                                        void* finalize_data,
                                        void* finalize_hint);
    
    • [in] env:调用 API 的环境。
    • [in] finalize_cb:原生回调,当 JavaScript 对象被垃圾回收时,将用于释放原生数据。napi_finalize 提供了更多详细信息。
    • [in] finalize_data:可选数据,将传递给 finalize_cb
    • [in] finalize_hint:传递给终结回调的可选上下文提示。

    如果 API 调用成功,则返回 napi_ok

    计划在事件循环中异步调用 napi_finalize 回调。

    通常,终结器在 GC(垃圾回收器)收集对象时被调用。此时,调用任何可能导致 GC 状态发生更改的 Node-API 都将被禁用,并会导致 Node.js 崩溃。

    node_api_post_finalizer 通过允许插件将对此类 Node-API 的调用推迟到 GC 终结之外的时间点,来帮助解决此限制。

    简单的异步操作#

    插件模块通常需要在其实现中利用 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 回调中。在 execute 回调中避免使用 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(node_api_basic_env env,
                                      napi_async_work work);
    

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

    调用 napi_cancel_async_work 后,将以 napi_cancelled 的状态值调用 complete 回调。即使工作被取消,也不应在 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:用户提供的数据上下文。这将传回给 execute 和 complete 函数。
    • [out] resultnapi_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(node_api_basic_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(node_api_basic_env env,
                                       napi_async_work work);
    
    • [in] env:调用 API 的环境。
    • [in] work:由 napi_create_async_work 调用返回的句柄。

    如果 API 调用成功,则返回 napi_ok

    此 API 取消已排队但尚未开始的工作。如果它已经开始执行,则无法取消,并将返回 napi_generic_failure。如果成功,将以 napi_cancelled 的状态值调用 complete 回调。即使它已被成功取消,也不应在 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 钩子,并且可以通过 async_hooks.executionAsyncResource() 访问。
    • [in] async_resource_name:用于 async_hooks API 公开的诊断信息的资源类型标识符。
    • [out] result:已初始化的异步上下文。

    如果 API 调用成功,则返回 napi_ok

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

    此 API 的以前版本在 napi_async_context 对象存在时没有保持对 async_resource 的强引用,而是期望调用者持有强引用。这种情况已经改变,因为无论如何,对于每个对 napi_async_init() 的调用,都必须对应调用 napi_async_destroy,以避免内存泄漏。

    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:表示要调用的 JavaScript 函数的 napi_value
    • [in] argcargv 数组中的元素数量。
    • [in] argv:表示函数参数的 JavaScript 值数组(作为 napi_value)。如果 argc 为零,则可以通过传入 NULL 来省略此参数。
    • [out] result:表示返回的 JavaScript 对象的 napi_value

    如果 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 或 Promise,都会在返回 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(node_api_basic_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(node_api_basic_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(node_api_basic_env env,
                                                        int64_t change_in_bytes,
                                                        int64_t* result);
    
    • [in] env:调用 API 的环境。
    • [in] change_in_bytes:由 JavaScript 对象保持活跃的外部已分配内存的变化量。
    • [out] result:调整后的值。此值应反映包含给定 change_in_bytes 的外部内存总量。不应依赖返回值的绝对值。例如,实现可能会为所有插件使用单个计数器,或为每个插件使用一个计数器。

    如果 API 调用成功,则返回 napi_ok

    此函数使运行时能够了解由 JavaScript 对象保持活跃的外部已分配内存量(即指向其自身由原生插件分配的内存的 JavaScript 对象)。注册外部已分配内存可能会(但不保证)比平时更频繁地触发全局垃圾回收。

    此函数的调用方式应确保插件不会减少超过其增加的外部内存量。

    Promise#

    Node-API 提供了创建 Promise 对象的工具,如 ECMA 规范的 Promise 对象部分 所述。它将 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 并将其传递给异步工作者:

    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() 将执行其异步动作,然后解析或拒绝延迟对象,从而完成 Promise 并释放延迟对象。

    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(),以分别解析或拒绝关联的 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 提供了一个用于使用底层 JavaScript 引擎执行包含 JavaScript 的字符串的 API。

    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(node_api_basic_env env,
                                                   struct uv_loop_s** loop);
    
    • [in] env:调用 API 的环境。
    • [out] loop:当前 libuv 循环实例。

    注意:虽然 libuv 随着时间的推移相对稳定,但它不提供 ABI 稳定性保证。应避免使用此函数。它的使用可能导致插件无法在不同 Node.js 版本间工作。异步线程安全函数调用 是许多用例的替代方案。

    异步线程安全函数调用#

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

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

    这些 API 提供了 napi_threadsafe_function 类型,以及创建、销毁和调用此类型对象的 API。napi_create_threadsafe_function() 创建对保存 JavaScript 函数的 napi_value 的持久引用,该函数可以从多个线程调用。调用是异步发生的。这意味着将要调用 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 参数提供的回调控制。call_js_cb 在主线程上为每次通过成功调用 napi_call_threadsafe_function() 放入队列的值被调用一次。如果未给出此类回调,将使用默认回调,并且生成的 JavaScript 调用将没有任何参数。call_js_cb 回调在它的参数中接收要调用的 JavaScript 函数作为 napi_value,以及创建 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

    在事件循环的每个 tick 中可能会调用零个或多个排队的项目。应用程序不应依赖除了调用回调的进度将会产生以及事件将随着时间的推移而被调用之外的任何特定行为。

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

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

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

    一旦使用 napi_threadsafe_function 的线程数达到零,任何进一步的线程都不能通过调用 napi_acquire_threadsafe_function() 开始使用它。事实上,所有后续与之关联的 API 调用(除了 napi_release_threadsafe_function())都将返回 napi_closing 的错误值。

    通过给 napi_release_threadsafe_function() 提供 napi_tsfn_abort 的值,可以“中止”线程安全函数。这将导致所有后续与该线程安全函数关联的 API(除了 napi_release_threadsafe_function())在引用计数达到零之前也返回 napi_closing。特别地,napi_call_threadsafe_function() 将返回 napi_closing,从而通知线程不再可能对该线程安全函数进行异步调用。这可以用作终止线程的标准。在从 napi_call_threadsafe_function() 收到 napi_closing 的返回值后,线程不得再使用该线程安全函数,因为它不再保证被分配。

    决定是否保持进程运行#

    与 libuv 句柄类似,线程安全函数可以被“引用(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 函数。如果为 call_js_cb 传入了 NULL,则必须提供此参数。
    • [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 函数。

    变更历史

    • 第 10 版 (NAPI_VERSION 定义为 10 或更高)

      call_js_cb 中抛出的未捕获异常将通过 'uncaughtException' 事件处理,而不是被忽略。

    napi_get_threadsafe_function_context#

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

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

    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 时,值才会被添加到队列中。

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

    napi_acquire_threadsafe_function#

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

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

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

    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 可能已被销毁。

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

    napi_ref_threadsafe_function#

    NAPI_EXTERN napi_status
    napi_ref_threadsafe_function(node_api_basic_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(node_api_basic_env env, napi_threadsafe_function func);
    
    • [in] env:调用 API 的环境。
    • [in] func:要取消引用的线程安全函数。

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

    此 API 只能从主线程调用。

    其他实用工具#

    node_api_get_module_file_name#

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

    如果插件加载过程在加载期间未能确定插件的文件名,则 result 可能是空字符串。