Node.js v18.18.2 文档


目录

Node-API#

稳定性:2 - 稳定

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

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

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 稳定性。C++ API 更容易使用。为了支持使用 C++,该项目维护了一个名为node-addon-api的 C++ 包装器模块。该包装器提供了可内联的 C++ API。使用node-addon-api构建的二进制文件将取决于 Node.js 导出的基于 Node-API C 的函数的符号。node-addon-api是编写调用 Node-API 的代码的更有效方法。以以下node-addon-api代码为例。第一部分显示了 node-addon-api代码,第二部分显示了插件中实际使用的内容。

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

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

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

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

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

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

ABI 稳定性的影响#

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

  • Node.js C++ API 可通过以下任一方式使用

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

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

    #include <v8.h> 

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

#include <node_api.h> 

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

架构#

与用 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++ 工具链才能成功安装本机插件。

节点 gyp#

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

从历史上看,node-gyp 一直是构建本机插件的首选工具。它得到了广泛的采用和记录。然而,一些开发人员遇到了 node-gyp 的限制。

CMake.js#

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

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

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

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

节点前 gyp#

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

预构建#

prebuild是一个支持使用 node-gyp 或 CMake.js 构建的工具。与支持多种服务器的nod​​e-pre-gyp不同,prebuild仅将二进制文件上传到GitHub版本。对于使用 CMake.js 的 GitHub 项目来说,预构建是一个不错的选择。

预构建#

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

用法#

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

#include <node_api.h> 

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

#define NAPI_VERSION 3
#include <node_api.h> 

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

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

#define NAPI_EXPERIMENTAL
#include <node_api.h> 

在这种情况下,整个 API 界面(包括任何实验性 API)将可供模块代码使用。

Node-API 版本矩阵#

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

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

* Node-API 是实验性的。

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

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

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

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

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

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

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

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

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

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

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

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

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

环境生命周期 API#

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

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

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

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

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

napi_set_instance_data#

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

如果 API 成功,则返回napi_ok

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

napi_get_instance_data#

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

如果 API 成功,则返回napi_ok

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

基本 Node-API 数据类型#

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

napi_status#

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

typedef enum {
  napi_ok,
  napi_invalid_arg,
  napi_object_expected,
  napi_string_expected,
  napi_name_expected,
  napi_function_expected,
  napi_number_expected,
  napi_boolean_expected,
  napi_array_expected,
  napi_generic_failure,
  napi_pending_exception,
  napi_cancelled,
  napi_escape_called_twice,
  napi_handle_scope_mismatch,
  napi_callback_scope_mismatch,
  napi_queue_full,
  napi_closing,
  napi_bigint_expected,
  napi_date_expected,
  napi_arraybuffer_expected,
  napi_detachable_arraybuffer_expected,
  napi_would_deadlock,  /* unused */
  napi_no_external_buffers_allowed,
  napi_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:UTF8 编码的字符串,包含与 VM 无关的错误描述。
  • engine_reserved:保留用于特定于 VM 的错误详细信息。目前尚未对任何虚拟机实现此功能。
  • engine_error_code:虚拟机特定的错误代码。目前尚未对任何虚拟机实现此功能。
  • error_code:源自上次错误的 Node-API 状态代码。

有关更多信息,请参阅错误处理部分。

napi_env#

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

napi_value#

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

napi_threadsafe_function#

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

napi_threadsafe_function_release_mode#

赋予napi_release_threadsafe_function()的值,以指示线程安全函数是立即关闭 ( napi_tsfn_abort ) 还是仅仅释放 ( napi_tsfn_release ),从而可用供后续通过 napi_acquire_threadsafe_function()napi_call_threadsafe_function()使用。

typedef enum {
  napi_tsfn_release,
  napi_tsfn_abort
} napi_threadsafe_function_release_mode; 

napi_threadsafe_function_call_mode#

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

typedef enum {
  napi_tsfn_nonblocking,
  napi_tsfn_blocking
} napi_threadsafe_function_call_mode; 

Node-API 内存管理类型#

napi_handle_scope#

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

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

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

napi_escapable_handle_scope#

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

napi_ref#

这是用于引用napi_value的抽象。这允许用户管理 JavaScript 值的生命周期,包括显式定义其最短生命周期。

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

napi_type_tag#

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

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

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

Node-API 回调类型#

napi_callback_info#

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

napi_callback#

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

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

除非出于对象生命周期管理中讨论的原因,否则不需要在napi_callback内创建句柄和/或回调作用域。

napi_finalize#

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

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

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

由于这些函数可能会在 JavaScript 引擎处于无法执行 JavaScript 代码的状态时被调用,因此 即使没有未决的异常,某些 Node-API 调用也可能会返回napi_pending_exception

对于node_api_create_external_string_latin1node_api_create_external_string_utf16 env参数可以为空,因为在环境关闭的后期可以收集外部字符串。

变更历史:

  • 实验性的(已定义NAPI_EXPERIMENTAL):

    当 JavaScript 引擎无法执行 JavaScript 时, 从终结器进行的 Node-API 调用将返回napi_cannot_run_js ;如果存在待处理的异常,则将返回napi_exception_pending

napi_async_execute_callback#

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

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

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

napi_async_complete_callback#

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

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

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

napi_threadsafe_function_call_js#

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

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

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

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

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

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

napi_cleanup_hook#

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

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

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

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

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

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

函数主体应启动异步清理操作,最后必须在对napi_remove_async_cleanup_hook 的调用中传递 handle

错误处理#

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

返回值#

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

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

如果返回的返回值不是napi_oknapi_pending_exception,则必须调用napi_is_exception_pending 来检查异常是否处于待处理状态。有关更多详细信息,请参阅有关例外的部分。

可能的napi_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(napi_env env,
                         const napi_extended_error_info** result); 
  • [in] env:调用 API 的环境。
  • [out] result:包含有关错误的更多信息的napi_extended_error_info结构。

如果 API 成功,则返回napi_ok

此 API 检索napi_extended_error_info结构,其中包含有关上次发生的错误的信息。

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

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

即使存在待处理的 JavaScript 异常,也可以调用此 API。

例外情况#

任何 Node-API 函数调用都可能导致待处理的 JavaScript 异常。任何 API 函数都属于这种情况,即使是那些可能不会导致 JavaScript 执行的函数。

如果函数返回的napi_statusnapi_ok,则没有异常处于待处理状态,并且不需要执行其他操作。如果 返回的napi_status不是napi_oknapi_pending_exception,为了尝试恢复并继续而不是简单地立即返回,napi_is_exception_pending必须 调用以确定异常是否处于待处理状态。

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

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

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

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

如果本机代码需要引发异常或确定napi_value是否是 JavaScript Error对象的实例,也可以使用以下实用函数:napi_throw_errornapi_throw_type_errornapi_throw_range_errornode_api_throw_syntax_errornapi_is_error

如果本机代码需要创建Error对象,还可以使用以下实用函数:napi_create_errornapi_create_type_errornapi_create_range_errornode_api_create_syntax_error,其中 result 是引用新创建的 JavaScript Error对象的 napi_value

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

originalName [code] 

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

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

如果 API 成功,则返回napi_ok

此 API 抛出提供的 JavaScript 值。

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

如果 API 成功,则返回napi_ok

此 API 会抛出 JavaScript Error以及所提供的文本。

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

如果 API 成功,则返回napi_ok

此 API 会抛出 JavaScript TypeError以及所提供的文本。

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

如果 API 成功,则返回napi_ok

此 API 会抛出 JavaScript RangeError以及所提供的文本。

node_api_throw_syntax_error#
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] msgnapi_value引用 JavaScript string用作Error的消息。
  • [out] resultnapi_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] msgnapi_value引用 JavaScript string用作Error的消息。
  • [out] resultnapi_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] msgnapi_value引用 JavaScript string用作Error的消息。
  • [out] resultnapi_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] msgnapi_value引用 JavaScript string用作Error的消息。
  • [out] resultnapi_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的形式返回。这些句柄必须保持对象“事件”,直到本机代码不再需要它们为止,否则在本机代码使用完它们之前可能会收集对象。

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

然而,在许多情况下,句柄的有效寿命必须比本机方法的寿命短或长。以下各节描述了可用于更改默认句柄寿命的 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 支持“可转义范围”以支持这种情况。可转义作用域允许“提升”一个句柄,使其“转义”当前作用域,并且句柄的生命周期从当前作用域更改为外部作用域。

可用于打开/关闭可转义范围的方法是 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] resultnapi_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] scopenapi_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] resultnapi_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] scopenapi_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] scopenapi_value代表当前范围。
  • [in] escapeenapi_value表示要转义的JavaScript Object
  • [out] resultnapi_value表示 外部作用域中转义的Object的句柄。

如果 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关联的对象的所有后续调用都 将返回NULL,因为返回的napi_value。尝试调用 napi_reference_ref来获取其对象已被收集的引用会导致错误。

一旦插件不再需要引用,就必须将其删除。当引用被删除时,将不再阻止相应的对象被收集。未能删除持久引用会导致“内存泄漏”,持久引用的本机内存和堆上的相应对象将永远保留。

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

变更历史:

  • 实验性(已定义NAPI_EXPERIMENTAL):

    可以为所有值类型创建引用。新支持的值类型不支持弱引用语义,当引用计数变为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] resultnapi_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] refnapi_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] refnapi_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] resultnapi_ref引用的napi_value

如果 API 成功,则返回napi_ok

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

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

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

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

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

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(napi_env env,
                                                     void (*fun)(void* arg),
                                                     void* arg); 

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

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

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

注册hook ,它是一个 napi_async_cleanup_hook类型的函数,作为一个函数,一旦当前Node.js 环境退出。

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回调中的释放后使用,插件应使用 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对象。为了方便起见,通过exports参数向 Init方法传递一个空对象。如果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;
} 

定义一个类以便可以创建新实例(通常与 Object wrap一起使用):

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

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

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

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

  return exports;
} 

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

NAPI_MODULE_INIT() {
  napi_value answer;
  napi_status result;

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

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

  return exports;
} 

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

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

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

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

使用 JavaScript 值#

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

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

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

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

枚举类型#

napi_key_collection_mode#
typedef enum {
  napi_key_include_prototypes,
  napi_key_own_only
} napi_key_collection_mode; 

描述Keys/Properties过滤器枚举:

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

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

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

属性过滤器位。可以对它们进行或运算来构建复合过滤器。

napi_key_conversion#
typedef enum {
  napi_key_keep_numbers,
  napi_key_numbers_to_strings
} napi_key_conversion; 

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

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

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

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

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

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

对象创建函数#

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

如果 API 成功,则返回napi_ok

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

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

如果 API 成功,则返回napi_ok

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

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

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

如果 API 成功,则返回napi_ok

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

ECMAScript 语言规范第 24.1 节中描述了 JavaScript 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:一个napi_value代表一个node::Buffer

如果 API 成功,则返回napi_ok

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

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

如果 API 成功,则返回napi_ok

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

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

如果 API 成功,则返回napi_ok

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

此 API 分配一个 JavaScript Date对象。

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

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

如果 API 成功,则返回napi_ok

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

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

此 API 返回与 JavaScript ArrayBuffer对应的 Node-API 值。ArrayBuffer的底层字节缓冲区是外部分配和管理的。调用者必须确保字节缓冲区保持有效,直到调用 Finalize 回调。

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

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

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

如果 API 成功,则返回napi_ok

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

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

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

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

对于 Node.js >=4 BuffersUint8Array s。

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

如果 API 成功,则返回napi_ok

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

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

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

如果 API 成功,则返回napi_ok

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

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

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

如果 API 成功,则返回napi_ok

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

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

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

如果 API 成功,则返回napi_ok

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

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

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

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

如果 API 成功,则返回napi_ok

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

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

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

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

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

如果 API 成功,则返回napi_ok

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

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

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

如果 API 成功,则返回napi_ok

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

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

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

如果 API 成功,则返回napi_ok

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

JavaScript number类型在 ECMAScript 语言规范第 6.1.6 节中进行了描述。请注意, 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 语言规范第 6.1.6 节中进行了描述 。

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

如果 API 成功,则返回napi_ok

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

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

如果 API 成功,则返回napi_ok

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

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

如果 API 成功,则返回napi_ok

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

生成的BigInt计算如下: (–1) sign_bit ( words[0] × (2 64 ) 0 + words[1] × (2 64 ) 1 + …)

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

如果 API 成功,则返回napi_ok

此 API从 ISO-8859-1 编码的 C 字符串创建 JavaScript string值。复制本机字符串。

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

node_api_create_external_string_latin1#

稳定性:1 - 实验性

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:加载项运行的环境。如果字符串是作为工作线程或主 Node.js 实例终止的一部分而被收集的,则该值可能为 null。
    • [in] data :这是作为void* 指针的值str
    • [in] finalize_hint :这是赋予 API 的 值finalize_hintnapi_finalize提供更多详细信息。该参数是可选的。传递 null 值意味着在收集相应的 JavaScript 字符串时不需要通知加载项。
  • [in] finalize_hint:在收集期间传递给 Finalize 回调的可选提示。
  • [out] result:代表 JavaScript stringnapi_value
  • [out] copied:字符串是否被复制。如果是,则终结器将已被调用以销毁str

如果 API 成功,则返回napi_ok

此 API从 ISO-8859-1 编码的 C 字符串创建 JavaScript string值。本机字符串不能被复制,因此必须在 JavaScript 值的整个生命周期中存在。

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

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

如果 API 成功,则返回napi_ok

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

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

node_api_create_external_string_utf16#

稳定性:1 - 实验性

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:加载项运行的环境。如果字符串是作为工作线程或主 Node.js 实例终止的一部分而被收集的,则该值可能为 null。
    • [in] data :这是作为void*指针的值str
    • [in] finalize_hint :这是赋予 API 的 值finalize_hintnapi_finalize提供更多详细信息。该参数是可选的。传递 null 值意味着在收集相应的 JavaScript 字符串时不需要通知加载项。
  • [in] finalize_hint:在收集期间传递给 Finalize 回调的可选提示。
  • [out] result:代表 JavaScript stringnapi_value
  • [out] copied:字符串是否被复制。如果是,则终结器将已被调用来销毁str

如果 API 成功,则返回napi_ok

此 API从 UTF16-LE 编码的 C 字符串创建 JavaScript string值。本机字符串不能被复制,因此必须在 JavaScript 值的整个生命周期中存在。

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

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

如果 API 成功,则返回napi_ok

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

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

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

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

如果 API 成功,则返回napi_ok

此 API 返回数组的长度。

ECMAScript 语言规范第 22.1.4.1 节中描述了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] arraybuffernapi_value代表正在查询的ArrayBuffer
  • [out] dataArrayBuffer的底层数据缓冲区。如果 byte_length 为0,则这可以是NULL或任何其他指针值。
  • [out] byte_length:基础数据缓冲区的长度(以字节为单位)。

如果 API 成功,则返回napi_ok

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

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

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

如果 API 成功,则返回napi_ok

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

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

napi_get_prototype#
napi_status napi_get_prototype(napi_env env,
                               napi_value object,
                               napi_value* result) 
  • [in] env:调用 API 的环境。
  • [in] objectnapi_value表示要返回其原型的JavaScript Object 。这将返回Object.getPrototypeOf的等效项(与函数的prototype属性不同)。
  • [out] resultnapi_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] typedarraynapi_value表示要查询其属性的TypedArray
  • [out] typeTypedArray中元素的标量数据类型。
  • [out] lengthTypedArray中的元素数量。
  • [out] dataTypedArray下的数据缓冲区由byte_offset值调整,以便它指向 TypedArray中的第一个元素。如果数组的长度是0,则这可以是NULL或任何其他指针值。
  • [out] arraybufferTypedArray底层的ArrayBuffer
  • [out] byte_offset:底层本机数组中数组第一个元素所在的字节偏移量。data 参数的值已调整,以便 data 指向数组中的第一个元素。因此,本机数组的第一个字节将位于 data - byte_offset

如果 API 成功,则返回napi_ok

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

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

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

napi_get_dataview_info#
napi_status napi_get_dataview_info(napi_env env,
                                   napi_value dataview,
                                   size_t* byte_length,
                                   void** data,
                                   napi_value* arraybuffer,
                                   size_t* byte_offset) 
  • [in] env:调用 API 的环境。
  • [in] dataviewnapi_value表示要查询其属性的DataView
  • [out] byte_lengthDataView中的字节数。
  • [out] dataDataView底层的数据缓冲区。如果 byte_length 为0,则这可以是NULL或任何其他指针值。
  • [out] arraybufferDataView之下的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] valuenapi_value表示 JavaScript Date
  • [out] result :以double形式表示的时间值,表示自 UTC 1970 年 1 月 1 日午夜以来的毫秒数。

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

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

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

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

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

此 API 返回与给定 JavaScript Boolean等效的 C 布尔基元 。

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

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

此 API 返回与给定 JavaScript number等效的 C 双基元 。

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

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

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

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

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

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

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

如果 API 成功,则返回napi_ok

此 API 将单个BigInt值转换为符号位、64 位小端数组以及数组中的元素数量。sign_bitwords可以都设置为NULL,以便仅获取word_count

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

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

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

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

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

此 API 返回与给定 JavaScript number等效的C int32原语。

如果数字超出 32 位整数的范围,则结果将被截断为相当于底部 32 位。如果该值 > 2 31 - 1 ,这可能会导致较大的正数变成负数。

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

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

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

此 API 返回与给定 JavaScript number 等效的C int64 原语。

number值在Number.MIN_SAFE_INTEGER -(2**53 - 1) - Number.MAX_SAFE_INTEGER (2**53 - 1)范围之外将失去精度。

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

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

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

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

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

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

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

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

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

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

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

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

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

获取全局实例的函数#

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

如果 API 成功,则返回napi_ok

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

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

如果 API 成功,则返回napi_ok

此 API 返回global对象。

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

如果 API 成功,则返回napi_ok

此 API 返回null对象。

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

如果 API 成功,则返回napi_ok

此 API 返回未定义的对象。

使用 JavaScript 值和抽象操作#

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

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

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

napi_coerce_to_bool#

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

如果 API 成功,则返回napi_ok

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

napi_coerce_to_number#

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

如果 API 成功,则返回napi_ok

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

napi_coerce_to_object#

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

如果 API 成功,则返回napi_ok

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

napi_coerce_to_string#

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

如果 API 成功,则返回napi_ok

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

napi_typeof#

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

如果 API 成功,则返回napi_ok

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

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

  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 语言规范第 12.10.4 节中所定义。

napi_is_array#

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

如果 API 成功,则返回napi_ok

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

napi_is_arraybuffer#

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

如果 API 成功,则返回napi_ok

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

napi_is_buffer#

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

如果 API 成功,则返回napi_ok

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

napi_is_date#

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

如果 API 成功,则返回napi_ok

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

napi_is_error#

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

如果 API 成功,则返回napi_ok

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

napi_is_typedarray#

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

如果 API 成功,则返回napi_ok

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

napi_is_dataview#

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

如果 API 成功,则返回napi_ok

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

napi_strict_equals#

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

如果 API 成功,则返回napi_ok

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

napi_detach_arraybuffer#

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

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

一般来说,如果ArrayBuffer之前已分离过,则它是不可分离的。引擎可能会对ArrayBuffer是否可拆卸施加附加条件。例如,V8 要求ArrayBuffer是外部的,即使用napi_create_external_arraybuffer创建。

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

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] resultarraybuffer是否分离。

如果 API 成功,则返回napi_ok

如果ArrayBuffer的内部数据为null ,则该 ArrayBuffer被视为分离。

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

使用 JavaScript 属性#

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

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

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

Node-API 值由类型napi_value表示。任何需要 JavaScript 值的 Node-API 调用都会采用napi_value。但是,调用者有责任确保 相关的napi_value属于 API 所需的 JavaScript 类型。

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

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

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

可以使用带有以下代码片段的 Node-API 值来完成等效操作:

napi_status status = napi_generic_failure;

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

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

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

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

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

可以使用带有以下代码片段的 Node-API 值来完成等效操作:

napi_status status = napi_generic_failure;

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

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

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

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

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

以下是 Node-API 对应部分的近似等效项:

napi_status status = napi_generic_failure;

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

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

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

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

以下是 Node-API 对应部分的近似等效项:

napi_status status = napi_status_generic_failure;

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

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

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

结构#

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

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

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

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

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

  • napi_default:未在属性上设置显式属性。默认情况下,属性是只读的,不可枚举且不可配置。
  • napi_writable:该属性可写。
  • napi_enumerable:该属性是可枚举的。
  • napi_configurable:该属性是可配置的,如 ECMAScript 语言规范6.1.7.1 节中所定义。
  • napi_static:该属性将被定义为类上的静态属性,而不是默认的实例属性。仅由napi_define_class使用 。它被napi_define_properties忽略。
  • napi_default_method:与 JS 类中的方法一样,该属性是可配置和可写的,但不可枚举。
  • napi_default_jsproperty:与 JavaScript 中通过赋值设置的属性一样,该属性是可写、可枚举和可配置的。
napi_property_descriptor#
typedef struct {
  // One of utf8name or name should be NULL.
  const char* utf8name;
  napi_value name;

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

  napi_property_attributes attributes;
  void* data;
} napi_property_descriptor; 
  • utf8name:描述属性键的可选字符串,编码为 UTF8。必须为该属性提供utf8namename之一。
  • name:可选的napi_value,指向要用作属性键的 JavaScript 字符串或符号。必须为该属性提供utf8namename之一。
  • value:如果属性是数据属性,则通过属性的 get 访问权限检索到的值。如果传入此值,请将gettersettermethoddata设置为NULL(因为这些成员不会被使用)。
  • getter:执行属性的 get 访问时调用的函数。如果传入此值,请将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:表示对象属性名称的 JavaScript 值数组的 napi_value 。该 API 可用于使用 napi_get_array_lengthnapi_get_element迭代 result

如果 API 成功,则返回napi_ok

此 API以字符串数组的形式返回object的可枚举属性的名称。键为符号的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:表示对象属性名称的 JavaScript 值数组的 napi_valuenapi_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

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

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

如果 API 成功,则返回napi_ok

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

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

如果 API 成功,则返回napi_ok

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

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

如果 API 成功,则返回napi_ok

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

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

如果 API 成功,则返回napi_ok

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

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

如果 API 成功,则返回napi_ok

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

napi_delete_element#
napi_status napi_delete_element(napi_env env,
                                napi_value object,
                                uint32_t index,
                                bool* result); 
  • [in] env:调用 Node-API 的环境。
  • [in] object:要查询的对象。
  • [in] index:要删除的属性的索引。
  • [out] result:元素删除是否成功。可以选择通过传递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 将一次设置一个对象的属性,如 DefineOwnProperty()所定义(在ECMA-262 规范的第 9.1.6 节中进行了描述)。

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

如果 API 成功,则返回napi_ok

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

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

如果 API 成功,则返回napi_ok

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

使用 JavaScript 函数#

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

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

此外,Node-API 提供了一组允许从本机代码调用 JavaScript 函数的函数。我们可以像常规 JavaScript 函数调用一样调用函数,也可以将其作为构造函数来调用。

通过napi_property_descriptor 项的 data 字段 传递到此 API的任何非NULL 数据都可以与object关联并释放每当通过将object和数据传递给 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] funcnapi_value表示要调用的 JavaScript 函数。
  • [in] argcargv数组中的元素计数。
  • [in] argv :表示作为函数参数传递的 JavaScript 值的napi_values数组。
  • [out] resultnapi_value表示返回的 JavaScript 对象。

如果 API 成功,则返回napi_ok

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

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

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

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

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

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

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

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

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

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

napi_create_function#

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

如果 API 成功,则返回napi_ok

该 API 允许附加组件作者在本机代码中创建函数对象。这是允许从JavaScript调用附加组件的本机代码的 主要机制。

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

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

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

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

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

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

  return exports;
}

NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) 

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

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

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

通过data参数传递到此 API 的任何非NULL数据都可以与生成的 JavaScript 函数(在result参数中返回 )关联每当函数被垃圾收集时,通过将 JavaScript 函数和数据传递给napi_add_finalizer释放它。

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

napi_get_cb_info#

napi_status napi_get_cb_info(napi_env env,
                             napi_callback_info cbinfo,
                             size_t* argc,
                             napi_value* argv,
                             napi_value* thisArg,
                             void** data) 
  • [in] env:调用 API 的环境。
  • [in] cbinfo:传入回调函数的回调信息。
  • [in-out] argc :指定所提供的argv数组的长度并接收参数的实际计数。可以选择通过传递NULL来忽略 argc
  • [out] argv :参数将复制到的napi_value的 C 数组。如果参数数量多于提供的数量,则仅复制请求数量的参数。如果提供的参数少于声明的参数,则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] consnapi_value表示要作为构造函数调用的 JavaScript 函数。
  • [in] argcargv数组中的元素计数。
  • [in] argv:JavaScript 值数组,作为napi_value表示构造函数的参数。如果argc为零,则可以通过传入NULL来省略此参数。
  • [out] resultnapi_value表示返回的 JavaScript 对象,在本例中是构造的对象。

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

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

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

可以使用以下代码片段在 N​​ode-API 中近似计算:

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

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

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

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

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

如果 API 成功,则返回napi_ok

对象包装#

Node-API 提供了一种“包装”C++ 类和实例的方法,以便可以从 JavaScript 调用类构造函数和方法。

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

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

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

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

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

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

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

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

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

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

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

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

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

类型标签是插件独有的 128 位整数。Node-API 提供了 napi_type_tag结构来存储类型标签。当这样的值与 JavaScript 对象或存储在napi_value中的外部一起传递到 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++ 类时,在检索放置在其中的 C++ 类实例后,可以从属性描述符中给定的静态函数调用 C++ 类的非静态数据属性、访问器和方法,而无需使用napi_static属性使用 napi_unwrap的 JavaScript 对象实例。

包装 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:传递给 Finalize 回调的可选上下文提示。
  • [out] result:对包装对象的可选引用。

如果 API 成功,则返回napi_ok

将本机实例包装在 JavaScript 对象中。稍后可以使用napi_unwrap()检索本机实例。

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

通常,在包装类实例时,应提供 Finalize 回调,该回调仅删除作为 Finalize 回调的data参数接收的本机实例。

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

注意:可选的返回引用(如果获得)应仅通过 napi_delete_reference删除,以响应最终回调调用。如果在此之前将其删除,则可能永远不会调用 Finalize 回调。因此,在获取引用时,还需要完成回调,以便能够正确处理引用。

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

对对象第二次调用napi_wrap()将返回错误。要将另一个本机实例与该对象关联,请首先使用napi_remove_wrap()

napi_unwrap#

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

如果 API 成功,则返回napi_ok

使用napi_wrap()检索先前包装在 JavaScript 对象中的本机实例。

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

napi_remove_wrap#

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

如果 API 成功,则返回napi_ok

使用napi_wrap()检索先前包装在 JavaScript 对象js_object中的本机实例并删除包装。如果 Finalize 回调与包装相关联,则当 JavaScript 对象被垃圾收集时,它将不再被调用。

napi_type_tag_object#

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

如果 API 成功,则返回napi_ok

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

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

napi_check_object_type_tag#

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

如果 API 成功,则返回napi_ok

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

napi_add_finalizer#

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

如果 API 成功,则返回napi_ok

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

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

注意:可选的返回引用(如果获得)应仅通过 napi_delete_reference删除以响应最终回调调用。如果在此之前将其删除,则可能永远不会调用 Finalize 回调。因此,在获取引用时,还需要完成回调,以便能够正确处理引用。

简单的异步操作#

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

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

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

executecomplete回调是分别在执行器准备好执行和完成任务时调用的函数。

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

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

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

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

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

napi_status napi_queue_async_work(napi_env env,
                                  napi_async_work work); 

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

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

napi_create_async_work#

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

如果 API 成功,则返回napi_ok

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

napi_cancel_async_work#

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

如果 API 成功,则返回napi_ok

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

即使存在待处理的 JavaScript 异常,也可以调用此 API。

自定义异步操作#

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

napi_async_init#

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

如果 API 成功,则返回napi_ok

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

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

napi_async_destroy#

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

如果 API 成功,则返回napi_ok

即使存在待处理的 JavaScript 异常,也可以调用此 API。

napi_make_callback#

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

如果 API 成功,则返回napi_ok

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

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

回调期间 JavaScript 在微任务队列上安排的任何process.nextTick或 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(napi_env env,
                                  const napi_node_version** version); 
  • [in] env:调用 API 的环境。
  • [out] version:指向 Node.js 本身版本信息的指针。

如果 API 成功,则返回napi_ok

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

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

napi_get_version#

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

如果 API 成功,则返回napi_ok

此 API 返回 Node.js 运行时支持的最高 Node-API 版本。Node-API 计划作为附​​加功能,以便 Node.js 的新版本可以支持其他 API 功能。为了允许插件在使用支持它的 Node.js 版本运行时使用较新的功能,同时在使用不支持它的 Node.js 版本运行时提供回退行为:

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

内存管理#

napi_adjust_external_memory#

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

如果 API 成功,则返回napi_ok

该函数为 V8 提供了由 JavaScript 对象(即指向由本机插件分配的其自己的内存的 JavaScript 对象)保持事件的外部分配内存量的指示。注册外部分配的内存将比其他情况更频繁地触发全局垃圾收集。

Promise #

Node-API 提供了创建Promise对象的工具,如ECMA 规范第 25.4 节中所述 。它将 Promise 实现为一对对象。当napi_create_promise()创建 Promise 时,会创建一个“延迟”对象并与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()将执行其异步操作,然后解析或拒绝 deferred,从而结束 Promise 并释放 deferred:

napi_deferred deferred;
napi_value undefined;
napi_status status;

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

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

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

napi_create_promise#

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

如果 API 成功,则返回napi_ok

该 API 创建一个延迟对象和一个 JavaScript Promise。

napi_resolve_deferred#

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

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

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

napi_is_promise#

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

脚本执行#

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

napi_run_script#

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

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

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

libuv 事件循环#

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

napi_get_uv_event_loop#

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

异步线程安全函数调用#

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

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

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

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

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

调用线程安全函数#

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

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

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

也可以通过将envcall_js_cb都设置为NULL来调用回调 ,以指示不再可能调用 JavaScript,而项目仍保留在队列中可能需要被释放。当 Node.js 进程退出而线程安全函数仍处于事件状态时,通常会发生这种情况。

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

在事件循环的每个周期中可以调用零个或多个排队项目。应用程序不应该依赖于特定的行为,除了随着时间的推移将进行调用回调的进度并且将调用事件之外。

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

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

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

一旦使用napi_threadsafe_function的线程数量达到零,其他线程就无法通过调用napi_acquire_threadsafe_function()来开始使用它 。事实上,与其关联的所有后续 API 调用(除napi_release_threadsafe_function()之外)都将返回错误值napi_closing

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

决定是否保持进程运行#

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

napi_unref_threadsafe_function既不会将线程安全函数标记为能够被销毁,也不会阻止其被销毁。

napi_create_threadsafe_function#

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

napi_get_threadsafe_function_context#

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

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

napi_call_threadsafe_function#

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

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

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

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

napi_acquire_threadsafe_function#

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

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

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

napi_release_threadsafe_function#

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

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

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

napi_ref_threadsafe_function#

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

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

napi_unref_threadsafe_function既不会将线程安全函数标记为能够被销毁,也不会阻止其被销毁。napi_acquire_threadsafe_functionnapi_release_threadsafe_function可用于此目的。

该 API 只能从主线程调用。

napi_unref_threadsafe_function#

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

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

该 API 只能从主线程调用。

杂项实用程序#

node_api_get_module_file_name#

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

如果加载项加载过程在加载过程中无法建立加载项的文件名,则result可能为空字符串。

NodeJS中文文档为Read dev Docs平台提供托管,中文NodeJS文档均由英文版NodeJS文档翻译,版权属于nodejs.org