Node-API 版本矩阵


【Node-API version matrix】

直到版本 9,Node-API 版本是累加的,并且独立于 Node.js 进行版本控制。这意味着任何版本都是对前一个版本的扩展,它包含了前一个版本的所有 API,并增加了一些新的 API。每个 Node.js 版本只支持一个 Node-API 版本。例如,v18.15.0 只支持 Node-API 版本 8。ABI 稳定性得以实现是因为版本 8 是所有先前版本的严格超集。

【Up until version 9, Node-API versions were additive and versioned independently from Node.js. This meant that any version was an extension to the previous version in that it had all of the APIs from the previous version with some additions. Each Node.js version only supported a single Node-API version. For example v18.15.0 supports only Node-API version 8. ABI stability was achieved because 8 was a strict superset of all previous versions.】

从版本 9 开始,虽然 Node-API 版本仍然独立版本化,但使用 Node-API 版本 9 的插件在升级到 Node-API 版本 10 时可能需要更新代码。然而,ABI 稳定性得以维持,因为支持高于 8 版本 Node-API 的 Node.js 版本,将支持从 8 到它们支持的最高版本之间的所有版本,并且默认提供版本 8 的 API,除非插件选择使用更高版本的 Node-API。这种方法在保持 ABI 稳定性的同时,也提供了更好地优化现有 Node-API 功能的灵活性。现有插件可以继续使用早期版本的 Node-API 运行而无需重新编译。如果插件需要使用更新版本 Node-API 的新功能,那么无论如何都需要修改现有代码并重新编译以使用这些新功能。

【As of version 9, while Node-API versions continue to be versioned independently, an add-on that ran with Node-API version 9 may need code updates to run with Node-API version 10. ABI stability is maintained, however, because Node.js versions that support Node-API versions higher than 8 will support all versions between 8 and the highest version they support and will default to providing the version 8 APIs unless an add-on opts into a higher Node-API version. This approach provides the flexibility of better optimizing existing Node-API functions while maintaining ABI stability. Existing add-ons can continue to run without recompilation using an earlier version of Node-API. If an add-on needs functionality from a newer Node-API version, changes to existing code and recompilation will be needed to use those new functions anyway.】

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

【In versions of Node.js that support Node-API version 9 and later, defining NAPI_VERSION=X and using the existing add-on initialization macros will bake in the requested Node-API version that will be used at runtime into the add-on. If NAPI_VERSION is not set it will default to 8.】

在较旧的版本中,此表可能不是最新的,最新的信息请参阅最新的 API 文档: Node-API 版本矩阵

【This table may not be up to date in older streams, the most up to date information is in the latest API documentation in: Node-API version matrix

Node-API 版本 支持
10 v22.14.0+、23.6.0+ 及所有后续版本
9: v18.17.0+、20.3.0+、21.0.0 及所有后续版本:
8 v12.22.0+、v14.17.0+、v15.12.0+、16.0.0 及所有后续版本
7: v10.23.0+、v12.19.0+、v14.12.0+、15.0.0 以及所有后续版本
6 v10.20.0+、v12.17.0+、14.0.0以及所有后续版本
5 v10.17.0+、v12.11.0+、13.0.0 和所有后续版本
v10.16.0+、v11.8.0+、12.0.0 以及所有后续版本
3 v6.14.2*、8.11.2+、v9.11.0+*、10.0.0 及所有后续版本
2 v8.10.0+*、v9.3.0+*、10.0.0 以及所有后续版本
v8.6.0+**、v9.0.0+*、10.0.0 及所有后续版本
  • Node-API 是实验性的。

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

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

【Each API documented for Node-API will have a header named added in:, and APIs which are stable will have the additional header Node-API version:. APIs are directly usable when using a Node.js version which supports the Node-API version shown in Node-API version: or higher. When using a Node.js version that does not support the Node-API version: listed or if there is no Node-API version: listed, then the API will only be available if #define NAPI_EXPERIMENTAL precedes the inclusion of node_api.h or js_native_api.h. If an API appears not to be available on a version of Node.js which is later than the one shown in added in: then this is most likely the reason for the apparent absence.】

严格与从本地代码访问 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 可能不适用。

【The Node-APIs associated strictly with accessing ECMAScript features from native code can be found separately in js_native_api.h and js_native_api_types.h. The APIs defined in these headers are included in node_api.h and node_api_types.h. The headers are structured in this way in order to allow implementations of Node-API outside of Node.js. For those implementations the Node.js specific APIs may not be applicable.】

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

【The Node.js-specific parts of an addon can be separated from the code that exposes the actual functionality to the JavaScript environment so that the latter may be used with multiple implementations of Node-API. In the example below, addon.c and addon.h refer only to js_native_api.h. This ensures that addon.c can be reused to compile against either the Node.js implementation of Node-API or any implementation of Node-API outside of Node.js.】

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

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

#define NODE_API_CALL(env, call)                                  \
  do {                                                            \
    napi_status status = (call);                                  \
    if (status != napi_ok) {                                      \
      const napi_extended_error_info* error_info = NULL;          \
      napi_get_last_error_info((env), &error_info);               \
      const char* err_message = error_info->error_message;        \
      bool is_pending;                                            \
      napi_is_exception_pending((env), &is_pending);              \
      /* If an exception is already pending, don't rethrow it */  \
      if (!is_pending) {                                          \
        const char* message = (err_message == NULL)               \
            ? "empty error message"                               \
            : err_message;                                        \
        napi_throw_error((env), NULL, message);                   \
      }                                                           \
      return NULL;                                                \
    }                                                             \
  } while(0)

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

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

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

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

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

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