Node-API#

穩定性:2 - 穩定

Node-API(以前稱為 N-API)是一個用於構建原生外掛的 API。它獨立於底層 JavaScript 執行時(例如 V8),並作為 Node.js 本身的一部分進行維護。該 API 在 Node.js 的各個版本中將保持應用二進位制介面(ABI)穩定。它旨在使外掛免受底層 JavaScript 引擎變化的影響,並允許為某個主要版本編譯的模組在後續主要版本的 Node.js 上執行而無需重新編譯。ABI 穩定性指南提供了更深入的解釋。

外掛的構建/打包方式與C++ 外掛部分所述的方法/工具相同。唯一的區別是原生程式碼使用的 API 集。不是使用 V8 或 Node.js 原生抽象 API,而是使用 Node-API 中提供的函式。

Node-API 公開的 API 通常用於建立和操作 JavaScript 值。概念和操作通常對映到 ECMA-262 語言規範中指定的思想。這些 API 具有以下屬性:

  • 所有 Node-API 呼叫都返回 napi_status 型別的狀態碼。此狀態表示 API 呼叫成功還是失敗。
  • API 的返回值透過 out 引數傳遞。
  • 所有 JavaScript 值都被抽象為一個名為 napi_value 的不透明型別。
  • 如果狀態碼錶示錯誤,可以使用 napi_get_last_error_info 獲取附加資訊。更多資訊可在錯誤處理部分錯誤處理中找到。

用各種程式語言編寫外掛#

Node-API 是一個 C API,它確保了 Node.js 版本和不同編譯器級別的 ABI 穩定性。有了這個穩定性保證,就可以在 Node-API 之上用其他程式語言編寫外掛。有關更多程式語言和引擎支援的詳細資訊,請參閱語言和引擎繫結

node-addon-api 是官方 C++ 繫結,它提供了更高效的方式來編寫呼叫 Node-API 的 C++ 程式碼。這個封裝器是一個只包含標頭檔案的庫,提供了一個可內聯的 C++ API。使用 node-addon-api 構建的二進位制檔案將依賴於 Node.js 匯出的 Node-API C 語言函式的符號。以下程式碼片段是 node-addon-api 的一個示例:

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

上述 node-addon-api C++ 程式碼等效於以下基於 C 的 Node-API 程式碼:

napi_status status;
napi_value object, string;
status = napi_create_object(env, &object);
if (status != napi_ok) {
  napi_throw_error(env, ...);
  return;
}

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

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

最終結果是外掛只使用匯出的 C API。即使外掛是用 C++ 編寫的,它仍然受益於 C Node-API 提供的 ABI 穩定性。

當使用 node-addon-api 而不是 C API 時,請從 node-addon-api 的 API 文件開始。

Node-API 資源為剛開始使用 Node-API 和 node-addon-api 的開發人員提供了很好的指導和技巧。其他媒體資源可以在 Node-API 媒體頁面上找到。

ABI 穩定性的含義#

儘管 Node-API 提供了 ABI 穩定性保證,但 Node.js 的其他部分則不提供,並且外掛使用的任何外部庫也可能不提供。特別是,以下任何 API 都不能跨主要版本提供 ABI 穩定性保證:

  • 透過以下任何方式可用的 Node.js C++ API:

    #include <node.h>
    #include <node_buffer.h>
    #include <node_version.h>
    #include <node_object_wrap.h> 
  • Node.js 中也包含的 libuv API,可透過以下方式獲取:

    #include <uv.h> 
  • 透過以下方式可用的 V8 API:

    #include <v8.h> 

因此,為了使外掛在 Node.js 主要版本之間保持 ABI 相容,它必須透過以下方式專門使用 Node-API:

#include <node_api.h> 

並檢查其使用的所有外部庫是否提供與 Node-API 類似的 ABI 穩定性保證。

ABI 穩定性中的列舉值#

Node-API 中定義的所有列舉資料型別都應視為固定大小的 int32_t 值。位標誌列舉型別應明確記錄,它們與位運算子(如位或 (|))作為位值一起工作。除非另有說明,否則列舉型別應被視為可擴充套件的。

新的列舉值將新增到列舉定義的末尾。列舉值不會被刪除或重新命名。

對於從 Node-API 函式返回的列舉型別,或作為 Node-API 函式的 out 引數提供的列舉型別,該值是一個整數值,外掛應處理未知值。允許在沒有版本保護的情況下引入新值。例如,在 switch 語句中檢查 napi_status 時,外掛應包含一個 default 分支,因為在新版 Node.js 中可能會引入新的狀態碼。

對於用作 in 引數的列舉型別,除非另有說明,將未知整數值傳遞給 Node-API 函式的結果是未定義的。新值是在版本保護下新增的,以指示引入它的 Node-API 版本。例如,napi_get_all_property_names 可以擴充套件為 napi_key_filter 的新列舉值。

對於在 in 引數和 out 引數中都使用的列舉型別,允許在沒有版本保護的情況下引入新值。

構建#

與用 JavaScript 編寫的模組不同,使用 Node-API 開發和部署 Node.js 原生外掛需要一套額外的工具。除了開發 Node.js 所需的基本工具之外,原生外掛開發人員還需要一個可以將 C 和 C++ 程式碼編譯成二進位制檔案的工具鏈。此外,根據原生外掛的部署方式,原生外掛的使用者也需要安裝 C/C++ 工具鏈。

對於 Linux 開發人員,必要的 C/C++ 工具鏈包易於獲得。GCC 在 Node.js 社群中被廣泛用於跨各種平臺進行構建和測試。對於許多開發人員來說,LLVM 編譯器基礎設施也是一個不錯的選擇。

對於 Mac 開發人員,Xcode 提供了所有必需的編譯器工具。但是,不必安裝整個 Xcode IDE。以下命令安裝必要的工具鏈:

xcode-select --install 

對於 Windows 開發人員,Visual Studio 提供了所有必需的編譯器工具。但是,不必安裝整個 Visual Studio IDE。以下命令安裝必要的工具鏈:

npm install --global windows-build-tools 

以下部分描述了用於開發和部署 Node.js 原生外掛的其他可用工具。

構建工具#

此處列出的兩個工具都要求原生外掛的使用者安裝 C/C++ 工具鏈,才能成功安裝原生外掛。

node-gyp#

node-gyp 是一個基於 Google 的 GYP 工具的 gyp-next 分支的構建系統,並與 npm 捆綁在一起。GYP,因此 node-gyp,要求安裝 Python。

歷史上,node-gyp 一直是構建原生外掛的首選工具。它得到了廣泛的採用和文件支援。然而,一些開發人員在使用 node-gyp 時遇到了限制。

CMake.js#

CMake.js 是一個基於 CMake 的替代構建系統。

CMake.js 是已經使用 CMake 的專案或受 node-gyp 限制影響的開發人員的不錯選擇。build_with_cmake 是一個基於 CMake 的原生外掛專案示例。

上傳預編譯二進位制檔案#

此處列出的三個工具允許原生外掛開發人員和維護人員建立二進位制檔案並將其上傳到公共或私有伺服器。這些工具通常與 Travis CI 和 AppVeyor 等 CI/CD 構建系統整合,以針對各種平臺和架構構建和上傳二進位制檔案。然後,這些二進位制檔案可供不需要安裝 C/C++ 工具鏈的使用者下載。

node-pre-gyp#

node-pre-gyp 是一個基於 node-gyp 的工具,增加了將二進位制檔案上傳到開發人員選擇的伺服器的能力。node-pre-gyp 對上傳二進位制檔案到 Amazon S3 有特別好的支援。

prebuild#

prebuild 是一個支援使用 node-gyp 或 CMake.js 進行構建的工具。與支援各種伺服器的 node-pre-gyp 不同,prebuild 只將二進位制檔案上傳到 GitHub releases。prebuild 是使用 CMake.js 的 GitHub 專案的不錯選擇。

prebuildify#

prebuildify 是一個基於 node-gyp 的工具。prebuildify 的優點是,當原生外掛上傳到 npm 時,構建的二進位制檔案會與原生外掛捆綁在一起。二進位制檔案從 npm 下載,並在安裝原生外掛時立即可供模組使用者使用。

用法#

為了使用 Node-API 函式,請包含位於 Node 開發樹 src 目錄中的檔案 node_api.h

#include <node_api.h> 

這將選擇給定 Node.js 版本的預設 NAPI_VERSION。為了確保與特定 Node-API 版本的相容性,可以在包含標頭檔案時顯式指定版本:

#define NAPI_VERSION 3
#include <node_api.h> 

這會將 Node-API 表面限制為僅指定(及更早)版本中可用的功能。

一些 Node-API 表面是實驗性的,需要顯式選擇加入:

#define NAPI_EXPERIMENTAL
#include <node_api.h> 

在這種情況下,整個 API 表面,包括任何實驗性 API,都將可用於模組程式碼。

偶爾會引入影響已釋出和穩定 API 的實驗性功能。這些功能可以透過選擇退出停用:

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

其中 <FEATURE_NAME> 是影響實驗性 API 和穩定 API 的實驗性功能的名稱。

Node-API 版本矩陣#

直到版本 9,Node-API 版本是累加的,並且與 Node.js 獨立版本化。這意味著任何版本都是前一個版本的擴充套件,因為它包含了前一個版本的所有 API 並增加了一些內容。每個 Node.js 版本只支援一個 Node-API 版本。例如,v18.15.0 只支援 Node-API 版本 8。ABI 穩定性之所以實現,是因為 8 是所有以前版本的嚴格超集。

從版本 9 開始,雖然 Node-API 版本仍然獨立版本化,但使用 Node-API 版本 9 執行的外掛可能需要程式碼更新才能使用 Node-API 版本 10。但是,ABI 穩定性得到了維護,因為支援 Node-API 版本高於 8 的 Node.js 版本將支援 8 和它們支援的最高版本之間的所有版本,並且將預設提供版本 8 的 API,除非外掛選擇加入更高的 Node-API 版本。這種方法提供了更好地最佳化現有 Node-API 函式的靈活性,同時保持了 ABI 穩定性。現有外掛可以繼續執行,無需重新編譯即可使用較早版本的 Node-API。如果外掛需要較新 Node-API 版本的功能,則需要更改現有程式碼並重新編譯才能使用這些新函式。

在支援 Node-API 版本 9 及更高版本的 Node.js 版本中,定義 NAPI_VERSION=X 並使用現有外掛初始化宏會將請求的 Node-API 版本烘焙到外掛中,該版本將在執行時使用。如果未設定 NAPI_VERSION,則預設為 8。

此表在較舊的流中可能不是最新的,最新資訊請參閱最新 API 文件:Node-API 版本矩陣

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

* Node-API 是實驗性的。

** Node.js 8.0.0 將 Node-API 作為實驗性功能包含在內。它作為 Node-API 版本 1 釋出,但一直髮展到 Node.js 8.6.0。API 在 Node.js 8.6.0 之前的版本中有所不同。我們建議使用 Node-API 版本 3 或更高版本。

Node-API 文件中的每個 API 都將有一個名為 added in: 的標題,穩定的 API 將有一個附加標題 Node-API version:。當使用支援 Node-API version: 中所示的 Node-API 版本或更高版本的 Node.js 版本時,API 可直接使用。當使用不支援所列 Node-API version: 的 Node.js 版本,或者未列出 Node-API version: 時,只有在包含 node_api.hjs_native_api.h 之前定義了 #define NAPI_EXPERIMENTAL 時,API 才可用。如果某個 API 在晚於 added in: 中所示的 Node.js 版本上似乎不可用,這很可能是其明顯缺失的原因。

嚴格與從原生程式碼訪問 ECMAScript 功能相關的 Node-API 可以在 js_native_api.hjs_native_api_types.h 中單獨找到。這些標頭檔案中定義的 API 包含在 node_api.hnode_api_types.h 中。標頭檔案以這種方式構造,以便允許在 Node.js 之外實現 Node-API。對於這些實現,特定於 Node.js 的 API 可能不適用。

外掛中特定於 Node.js 的部分可以與將實際功能暴露給 JavaScript 環境的程式碼分離,以便後者可以與 Node-API 的多個實現一起使用。在下面的示例中,addon.caddon.h 只引用 js_native_api.h。這確保了 addon.c 可以重用以針對 Node.js 實現的 Node-API 或 Node.js 之外的任何 Node-API 實現進行編譯。

addon_node.c 是一個單獨的檔案,其中包含外掛的 Node.js 特定入口點,並在外掛載入到 Node.js 環境時透過呼叫 addon.c 來例項化外掛。

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

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

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

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

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

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

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

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

環境生命週期 API#

ECMAScript 語言規範代理部分將“代理”定義為 JavaScript 程式碼執行的自包含環境。程序可以併發或按順序啟動和終止多個此類代理。

一個 Node.js 環境對應一個 ECMAScript 代理。在主程序中,環境在啟動時建立,並且可以在單獨的執行緒上建立額外的環境,以充當工作執行緒。當 Node.js 嵌入到另一個應用程式中時,應用程式的主執行緒在其應用程式程序的生命週期內也可以多次構造和銷燬 Node.js 環境,從而應用程式建立的每個 Node.js 環境又可以在其生命週期內建立和銷燬額外的工作執行緒環境。

從原生外掛的角度來看,這意味著它提供的繫結可能會被多次呼叫,從多個上下文,甚至併發地從多個執行緒呼叫。

原生外掛可能需要分配在 Node.js 環境生命週期中使用的全域性狀態,以便該狀態對於外掛的每個例項都是唯一的。

為此,Node-API 提供了一種關聯資料的方式,使其生命週期與 Node.js 環境的生命週期繫結。

napi_set_instance_data#

napi_status napi_set_instance_data(node_api_basic_env env,
                                   void* data,
                                   napi_finalize finalize_cb,
                                   void* finalize_hint); 
  • [in] env: 呼叫 Node-API 的環境。
  • [in] data: 要提供給此例項繫結的資料項。
  • [in] finalize_cb: 當環境被銷燬時呼叫的函式。該函式接收 data,以便可以釋放它。napi_finalize 提供了更多詳細資訊。
  • [in] finalize_hint: 在收集期間傳遞給終結回撥的可選提示。

如果 API 成功,則返回 napi_ok

此 API 將 data 與當前執行的 Node.js 環境關聯起來。data 隨後可以使用 napi_get_instance_data() 檢索。任何透過之前對 napi_set_instance_data() 的呼叫設定的與當前執行的 Node.js 環境關聯的現有資料都將被覆蓋。如果之前的呼叫提供了 finalize_cb,則不會呼叫它。

napi_get_instance_data#

napi_status napi_get_instance_data(node_api_basic_env env,
                                   void** data); 
  • [in] env: 呼叫 Node-API 的環境。
  • [out] data: 之前透過呼叫 napi_set_instance_data() 與當前執行的 Node.js 環境關聯的資料項。

如果 API 成功,則返回 napi_ok

此 API 檢索之前透過 napi_set_instance_data() 與當前執行的 Node.js 環境關聯的資料。如果未設定資料,則呼叫將成功,並將 data 設定為 NULL

基本 Node-API 資料型別#

Node-API 公開以下基本資料型別作為各種 API 消耗的抽象。這些 API 應被視為不透明的,只能透過其他 Node-API 呼叫進行內省。

napi_status#

指示 Node-API 呼叫成功或失敗的整數狀態碼。目前支援以下狀態碼。

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

如果 API 返回失敗狀態後需要額外資訊,可以透過呼叫 napi_get_last_error_info 獲取。

napi_extended_error_info#

typedef struct {
  const char* error_message;
  void* engine_reserved;
  uint32_t engine_error_code;
  napi_status error_code;
} napi_extended_error_info; 
  • error_message: 包含錯誤 VM 中立描述的 UTF8 編碼字串。
  • engine_reserved: 保留用於 VM 特定錯誤詳細資訊。目前未針對任何 VM 實現。
  • engine_error_code: VM 特定錯誤碼。目前未針對任何 VM 實現。
  • error_code: 源自上次錯誤的 Node-API 狀態碼。

有關更多資訊,請參閱錯誤處理部分。

napi_env#

napi_env 用於表示底層 Node-API 實現可用於持久化 VM 特定狀態的上下文。此結構在呼叫原生函式時傳遞給它們,並且在進行 Node-API 呼叫時必須傳遞回來。具體來說,當最初呼叫原生函式時傳遞的相同 napi_env 必須傳遞給任何後續巢狀的 Node-API 呼叫。出於一般重用目的快取 napi_env,以及在不同 Worker 執行緒上執行的同一外掛例項之間傳遞 napi_env 是不允許的。當原生外掛例項解除安裝時,napi_env 將失效。此事件的通知透過提供給 napi_add_env_cleanup_hooknapi_set_instance_data 的回撥進行傳遞。

node_api_basic_env#

穩定性:1 - 實驗性

napi_env 的此變體傳遞給同步終結器 (node_api_basic_finalize)。Node-API 的一個子集接受 node_api_basic_env 型別引數作為它們的第一個引數。這些 API 不訪問 JavaScript 引擎的狀態,因此可以安全地從同步終結器呼叫。允許將 napi_env 型別引數傳遞給這些 API,但是不允許將 node_api_basic_env 型別引數傳遞給訪問 JavaScript 引擎狀態的 API。在沒有強制轉換的情況下嘗試這樣做將導致編譯器警告或錯誤,當外掛使用導致它們在將不正確的指標型別傳遞給函式時發出警告和/或錯誤的標誌進行編譯時。從同步終結器呼叫此類 API 最終將導致應用程式終止。

napi_value#

這是一個不透明指標,用於表示 JavaScript 值。

napi_threadsafe_function#

這是一個不透明指標,表示一個 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 銷燬。關閉作用域可以向垃圾回收器指示,在控制代碼作用域生命週期內建立的所有 napi_values 不再從當前棧幀中引用。

有關更多詳細資訊,請查閱物件生命週期管理

napi_escapable_handle_scope#

可逃逸控制代碼作用域是一種特殊型別的控制代碼作用域,用於將特定控制代碼作用域內建立的值返回到父作用域。

napi_ref#

這是用於引用 napi_value 的抽象。這允許使用者管理 JavaScript 值的生命週期,包括顯式定義其最短生命週期。

有關更多詳細資訊,請查閱物件生命週期管理

napi_type_tag#

一個 128 位的值,儲存為兩個無符號的 64 位整數。它用作 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 內部建立控制代碼和/或回撥作用域不是必需的。

node_api_basic_finalize#

穩定性:1 - 實驗性

外掛提供的函式指標型別,允許使用者在外部擁有的資料準備好被清理時收到通知,因為與其關聯的物件已被垃圾回收。使用者必須提供一個滿足以下簽名的函式,該函式將在物件被回收時呼叫。目前,node_api_basic_finalize 可用於發現何時回收具有外部資料的物件。

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

除非出於物件生命週期管理中討論的原因,否則在函式體內部建立控制代碼和/或回撥作用域不是必需的。

由於這些函式可能在 JavaScript 引擎處於無法執行 JavaScript 程式碼的狀態下呼叫,因此只能呼叫接受 node_api_basic_env 作為其第一個引數的 Node-API。在當前垃圾回收週期完成後,可以使用 node_api_post_finalizer 來安排需要訪問 JavaScript 引擎狀態的 Node-API 呼叫執行。

node_api_create_external_string_latin1node_api_create_external_string_utf16的情況下,env引數可能為null,因為外部字串可以在環境關閉的後期被收集。

變更歷史

  • 實驗性 (NAPI_EXPERIMENTAL)

    只能呼叫接受 node_api_basic_env 作為其第一個引數的 Node-API,否則應用程式將以適當的錯誤訊息終止。此功能可以透過定義 NODE_API_EXPERIMENTAL_BASIC_ENV_OPT_OUT 來關閉。

napi_finalize#

外掛提供的函式指標型別,允許使用者在垃圾回收事件響應中,在垃圾回收週期完成後,安排一組對 Node-API 的呼叫。這些函式指標可以與 node_api_post_finalizer 一起使用。

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

變更歷史

  • 實驗性 (已定義 NAPI_EXPERIMENTAL)

    這種型別的函式可能不再用作終結器,除了與 node_api_post_finalizer 一起使用。必須改用 node_api_basic_finalize。此功能可以透過定義 NODE_API_EXPERIMENTAL_BASIC_ENV_OPT_OUT 來關閉。

napi_async_execute_callback#

與支援非同步操作的函式一起使用的函式指標。回撥函式必須滿足以下簽名:

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

此函式的實現必須避免進行執行 JavaScript 或與 JavaScript 物件互動的 Node-API 呼叫。Node-API 呼叫應改在 napi_async_complete_callback 中。請勿使用 napi_env 引數,因為它很可能導致 JavaScript 的執行。

napi_async_complete_callback#

與支援非同步操作的函式一起使用的函式指標。回撥函式必須滿足以下簽名:

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

除非出於物件生命週期管理中討論的原因,否則在函式體內部建立控制代碼和/或回撥作用域不是必需的。

napi_threadsafe_function_call_js#

與非同步執行緒安全函式呼叫一起使用的函式指標。回撥將在主執行緒上呼叫。其目的是使用從輔助執行緒透過佇列到達的資料項來構建呼叫 JavaScript 所需的引數,通常透過 napi_call_function,然後進行 JavaScript 呼叫。

透過佇列從輔助執行緒到達的資料在 data 引數中給出,要呼叫的 JavaScript 函式在 js_callback 引數中給出。

Node-API 在呼叫此回撥之前設定環境,因此透過 napi_call_function 而不是透過 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 呼叫的環境,如果執行緒安全函式正在銷燬且 data 可能需要釋放,則為 NULL
  • [in] js_callback: 要呼叫的 JavaScript 函式,如果執行緒安全函式正在銷燬且 data 可能需要釋放,則為 NULL。如果建立執行緒安全函式時沒有 js_callback,它也可以是 NULL
  • [in] context: 建立執行緒安全函式時使用的可選資料。
  • [in] data: 由輔助執行緒建立的資料。回撥負責將此原生資料轉換為 JavaScript 值(使用 Node-API 函式),這些值可以在呼叫 js_callback 時作為引數傳遞。此指標完全由執行緒和此回撥管理。因此,此回撥應釋放資料。

除非出於物件生命週期管理中討論的原因,否則在函式體內部建立控制代碼和/或回撥作用域不是必需的。

napi_cleanup_hook#

napi_add_env_cleanup_hook 一起使用的函式指標。當環境被銷燬時將呼叫它。

回撥函式必須滿足以下簽名:

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

napi_add_async_cleanup_hook 一起使用的函式指標。當環境被銷燬時將呼叫它。

回撥函式必須滿足以下簽名:

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

函式體應啟動非同步清理操作,在非同步清理完成後,必須將 handle 傳遞給 napi_remove_async_cleanup_hook

錯誤處理#

Node-API 使用返回值和 JavaScript 異常進行錯誤處理。以下部分解釋了每種情況的處理方法。

返回值#

所有 Node-API 函式都共享相同的錯誤處理模式。所有 API 函式的返回型別都是 napi_status

如果請求成功並且沒有丟擲未捕獲的 JavaScript 異常,則返回值為 napi_ok。如果發生錯誤並且丟擲了異常,則將返回錯誤對應的 napi_status 值。如果丟擲了異常但未發生錯誤,則將返回 napi_pending_exception

在返回除 napi_oknapi_pending_exception 之外的值的情況下,必須呼叫 napi_is_exception_pending 來檢查是否有異常待處理。有關詳細資訊,請參閱異常部分。

所有可能的 napi_status 值都在 napi_api_types.h 中定義。

napi_status 返回值提供了一種 VM 獨立的錯誤表示。在某些情況下,獲取更詳細的資訊非常有用,包括表示錯誤的字串以及 VM(引擎)特定的資訊。

為了檢索此資訊,提供了 napi_get_last_error_info,它返回一個 napi_extended_error_info 結構。napi_extended_error_info 結構的格式如下:

typedef struct napi_extended_error_info {
  const char* error_message;
  void* engine_reserved;
  uint32_t engine_error_code;
  napi_status error_code;
}; 
  • error_message: 發生的錯誤的文字表示。
  • engine_reserved: 不透明控制代碼,僅供引擎使用。
  • engine_error_code: VM 特定錯誤程式碼。
  • error_code: 上一個錯誤的 Node-API 狀態碼。

napi_get_last_error_info 返回上次 Node-API 呼叫發生的資訊。

不要依賴任何擴充套件資訊的內容或格式,因為它不受 SemVer 約束,並且可能隨時更改。它僅用於日誌記錄目的。

napi_get_last_error_info#
napi_status
napi_get_last_error_info(node_api_basic_env env,
                         const napi_extended_error_info** result); 
  • [in] env: 呼叫 API 的環境。
  • [out] result: 包含更多錯誤資訊的 napi_extended_error_info 結構。

如果 API 成功,則返回 napi_ok

此 API 檢索包含上次發生錯誤資訊的 napi_extended_error_info 結構。

返回的 napi_extended_error_info 的內容僅在對同一 env 呼叫 Node-API 函式之前有效。這包括對 napi_is_exception_pending 的呼叫,因此通常需要複製資訊以便以後使用。error_message 中返回的指標指向一個靜態定義的字串,因此如果在呼叫另一個 Node-API 函式之前已將其從 error_message 欄位(將被覆蓋)中複製出來,則使用該指標是安全的。

不要依賴任何擴充套件資訊的內容或格式,因為它不受 SemVer 約束,並且可能隨時更改。它僅用於日誌記錄目的。

即使有待處理的 JavaScript 異常,也可以呼叫此 API。

異常#

任何 Node-API 函式呼叫都可能導致待處理的 JavaScript 異常。這適用於任何 API 函式,即使是那些可能不會導致 JavaScript 執行的函式。

如果函式返回的 napi_statusnapi_ok,則沒有異常待處理,無需額外操作。如果返回的 napi_status 不是 napi_oknapi_pending_exception,為了嘗試恢復並繼續而不是簡單地立即返回,必須呼叫 napi_is_exception_pending 來確定是否有異常待處理。

在許多情況下,當呼叫 Node-API 函式並且已經有異常待處理時,該函式將立即返回 napi_pending_exceptionnapi_status。然而,並非所有函式都如此。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] msg: 引用 JavaScript stringnapi_value,用作 Error 的訊息。
  • [out] result: 表示已建立錯誤的 napi_value

如果 API 成功,則返回 napi_ok

此 API 返回帶有提供的文字的 JavaScript Error

napi_create_type_error#
NAPI_EXTERN napi_status napi_create_type_error(napi_env env,
                                               napi_value code,
                                               napi_value msg,
                                               napi_value* result); 
  • [in] env: 呼叫 API 的環境。
  • [in] code: 可選的 napi_value,包含要與錯誤關聯的錯誤程式碼字串。
  • [in] msg: 引用 JavaScript stringnapi_value,用作 Error 的訊息。
  • [out] result: 表示已建立錯誤的 napi_value

如果 API 成功,則返回 napi_ok

此 API 返回帶有提供的文字的 JavaScript TypeError

napi_create_range_error#
NAPI_EXTERN napi_status napi_create_range_error(napi_env env,
                                                napi_value code,
                                                napi_value msg,
                                                napi_value* result); 
  • [in] env: 呼叫 API 的環境。
  • [in] code: 可選的 napi_value,包含要與錯誤關聯的錯誤程式碼字串。
  • [in] msg: 引用 JavaScript stringnapi_value,用作 Error 的訊息。
  • [out] result: 表示已建立錯誤的 napi_value

如果 API 成功,則返回 napi_ok

此 API 返回帶有提供的文字的 JavaScript RangeError

node_api_create_syntax_error#
NAPI_EXTERN napi_status node_api_create_syntax_error(napi_env env,
                                                     napi_value code,
                                                     napi_value msg,
                                                     napi_value* result); 
  • [in] env: 呼叫 API 的環境。
  • [in] code: 可選的 napi_value,包含要與錯誤關聯的錯誤程式碼字串。
  • [in] msg: 引用 JavaScript stringnapi_value,用作 Error 的訊息。
  • [out] result: 表示已建立錯誤的 napi_value

如果 API 成功,則返回 napi_ok

此 API 返回帶有提供的文字的 JavaScript SyntaxError

napi_get_and_clear_last_exception#
napi_status napi_get_and_clear_last_exception(napi_env env,
                                              napi_value* result); 
  • [in] env: 呼叫 API 的環境。
  • [out] result: 如果有異常待處理,則為異常,否則為 NULL

如果 API 成功,則返回 napi_ok

即使有待處理的 JavaScript 異常,也可以呼叫此 API。

napi_is_exception_pending#
napi_status napi_is_exception_pending(napi_env env, bool* result); 
  • [in] env: 呼叫 API 的環境。
  • [out] result: 如果有異常待處理,則設定為 true 的布林值。

如果 API 成功,則返回 napi_ok

即使有待處理的 JavaScript 異常,也可以呼叫此 API。

napi_fatal_exception#
napi_status napi_fatal_exception(napi_env env, napi_value err); 
  • [in] env: 呼叫 API 的環境。
  • [in] err: 傳遞給 'uncaughtException' 的錯誤。

在 JavaScript 中觸發一個 'uncaughtException'。如果非同步回撥丟擲異常且無法恢復,此功能非常有用。

致命錯誤#

當原生外掛中發生無法恢復的錯誤時,可以丟擲致命錯誤以立即終止程序。

napi_fatal_error#
NAPI_NO_RETURN void napi_fatal_error(const char* location,
                                     size_t location_len,
                                     const char* message,
                                     size_t message_len); 
  • [in] location: 發生錯誤的可選位置。
  • [in] location_len: 位置的位元組長度,如果以 null 結尾,則為 NAPI_AUTO_LENGTH
  • [in] message: 與錯誤關聯的訊息。
  • [in] message_len: 訊息的位元組長度,如果以 null 結尾,則為 NAPI_AUTO_LENGTH

函式呼叫不返回,程序將終止。

即使有待處理的 JavaScript 異常,也可以呼叫此 API。

物件生命週期管理#

當進行 Node-API 呼叫時,底層 VM 堆中物件的控制代碼可能以 napi_values 的形式返回。這些控制代碼必須保持物件“存活”,直到原生程式碼不再需要它們,否則物件可能在原生程式碼使用完之前就被回收。

當物件控制代碼返回時,它們與一個“作用域”關聯。預設作用域的生命週期與原生方法呼叫的生命週期繫結。結果是,預設情況下,控制代碼保持有效,並且與這些控制代碼關聯的物件將在原生方法呼叫的生命週期內保持存活。

然而,在許多情況下,控制代碼的生命週期需要比原生方法更短或更長。以下部分描述了可用於更改控制代碼生命週期(使其偏離預設值)的 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] result: 表示新作用域的 napi_value

如果 API 成功,則返回 napi_ok

此 API 開啟一個新的作用域。

napi_close_handle_scope#
NAPI_EXTERN napi_status napi_close_handle_scope(napi_env env,
                                                napi_handle_scope scope); 
  • [in] env: 呼叫 API 的環境。
  • [in] scope: 表示要關閉的作用域的 napi_value

如果 API 成功,則返回 napi_ok

此 API 關閉傳入的作用域。作用域必須按照建立的相反順序關閉。

即使有待處理的 JavaScript 異常,也可以呼叫此 API。

napi_open_escapable_handle_scope#
NAPI_EXTERN napi_status
    napi_open_escapable_handle_scope(napi_env env,
                                     napi_handle_scope* result); 
  • [in] env: 呼叫 API 的環境。
  • [out] result: 表示新作用域的 napi_value

如果 API 成功,則返回 napi_ok

此 API 開啟一個新作用域,其中一個物件可以被提升到外部作用域。

napi_close_escapable_handle_scope#
NAPI_EXTERN napi_status
    napi_close_escapable_handle_scope(napi_env env,
                                      napi_handle_scope scope); 
  • [in] env: 呼叫 API 的環境。
  • [in] scope: 表示要關閉的作用域的 napi_value

如果 API 成功,則返回 napi_ok

此 API 關閉傳入的作用域。作用域必須按照建立的相反順序關閉。

即使有待處理的 JavaScript 異常,也可以呼叫此 API。

napi_escape_handle#
napi_status napi_escape_handle(napi_env env,
                               napi_escapable_handle_scope scope,
                               napi_value escapee,
                               napi_value* result); 
  • [in] env: 呼叫 API 的環境。
  • [in] scope: 表示當前作用域的 napi_value
  • [in] escapee: 表示要逃逸的 JavaScript Objectnapi_value
  • [out] result: 表示外部作用域中逃逸 Object 控制代碼的 napi_value

如果 API 成功,則返回 napi_ok

此 API 提升 JavaScript 物件的控制代碼,使其在外部作用域的生命週期內有效。每個作用域只能呼叫一次。如果呼叫多次,將返回錯誤。

即使有待處理的 JavaScript 異常,也可以呼叫此 API。

對生命週期長於原生方法的值的引用#

在某些情況下,外掛需要能夠建立和引用生命週期長於單個原生方法呼叫的值。例如,要建立一個建構函式並在以後使用該建構函式請求建立例項,必須能夠跨許多不同的例項建立請求引用建構函式物件。這對於作為 napi_value 返回的普通控制代碼是不可能實現的,如前一節所述。普通控制代碼的生命週期由作用域管理,所有作用域都必須在原生方法結束之前關閉。

Node-API 提供了建立對值的持久引用的方法。目前,Node-API 只允許為有限的值型別集建立引用,包括物件、外部物件、函式和符號。

每個引用都有一個關聯的計數,值為 0 或更高,它決定了引用是否會保持相應的值存活。計數為 0 的引用不會阻止值被回收。物件(物件、函式、外部物件)和符號型別的值正在變為“弱”引用,並且在未被回收時仍然可以訪問。任何大於 0 的計數都將阻止值被回收。

符號值有不同的風格。真正的弱引用行為僅由使用 napi_create_symbol 函式或 JavaScript Symbol() 建構函式呼叫建立的區域性符號支援。使用 node_api_symbol_for 函式或 JavaScript Symbol.for() 函式呼叫建立的全域性註冊符號始終保持強引用,因為垃圾回收器不會回收它們。對於眾所周知的符號(例如 Symbol.iterator)也是如此。它們也永遠不會被垃圾回收器回收。

可以建立具有初始引用計數的引用。然後可以透過 napi_reference_refnapi_reference_unref 修改計數。如果物件在引用計數為 0 時被回收,則所有後續獲取與引用關聯的物件的呼叫 napi_get_reference_value 將為返回的 napi_value 返回 NULL。嘗試對物件已被回收的引用呼叫 napi_reference_ref 將導致錯誤。

一旦外掛不再需要引用,就必須刪除它們。當引用被刪除時,它將不再阻止相應的物件被回收。未能刪除持久引用會導致“記憶體洩漏”,持久引用的原生記憶體和堆上相應的物件都將永遠保留。

可以建立多個持久引用來引用同一個物件,每個引用將根據其各自的計數來決定是否使該物件保持存活。對同一物件的多個持久引用可能會意外地保持原生記憶體的存活。持久引用的原生結構必須保持存活,直到對引用物件的終結器執行。如果為同一物件建立了新的持久引用,則不會執行該物件的終結器,並且指向早期持久引用的原生記憶體將不會被釋放。可以透過在可能的情況下除了 napi_reference_unref 之外還呼叫 napi_delete_reference 來避免這種情況。

變更歷史

  • 版本 10 (已定義 NAPI_VERSION10 或更高)

    可以為所有值型別建立引用。新支援的值型別不支援弱引用語義,並且這些型別的值在引用計數變為 0 時被釋放,並且無法再從引用中訪問。

napi_create_reference#
NAPI_EXTERN napi_status napi_create_reference(napi_env env,
                                              napi_value value,
                                              uint32_t initial_refcount,
                                              napi_ref* result); 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 正在為其建立引用的 napi_value
  • [in] initial_refcount: 新引用的初始引用計數。
  • [out] result: 指向新引用的 napi_ref

如果 API 成功,則返回 napi_ok

此 API 建立一個新引用,其引用計數為指定值,指向傳入的值。

napi_delete_reference#
NAPI_EXTERN napi_status napi_delete_reference(napi_env env, napi_ref ref); 
  • [in] env: 呼叫 API 的環境。
  • [in] ref: 要刪除的 napi_ref

如果 API 成功,則返回 napi_ok

此 API 刪除傳入的引用。

即使有待處理的 JavaScript 異常,也可以呼叫此 API。

napi_reference_ref#
NAPI_EXTERN napi_status napi_reference_ref(napi_env env,
                                           napi_ref ref,
                                           uint32_t* result); 
  • [in] env: 呼叫 API 的環境。
  • [in] ref: 引用計數將遞增的 napi_ref
  • [out] result: 新的引用計數。

如果 API 成功,則返回 napi_ok

此 API 遞增傳入引用的引用計數並返回結果引用計數。

napi_reference_unref#
NAPI_EXTERN napi_status napi_reference_unref(napi_env env,
                                             napi_ref ref,
                                             uint32_t* result); 
  • [in] env: 呼叫 API 的環境。
  • [in] ref: 引用計數將遞減的 napi_ref
  • [out] result: 新的引用計數。

如果 API 成功,則返回 napi_ok

此 API 遞減傳入引用的引用計數並返回結果引用計數。

napi_get_reference_value#
NAPI_EXTERN napi_status napi_get_reference_value(napi_env env,
                                                 napi_ref ref,
                                                 napi_value* result); 
  • [in] env: 呼叫 API 的環境。
  • [in] ref: 正在請求其對應值的 napi_ref
  • [out] result: 由 napi_ref 引用的 napi_value

如果 API 成功,則返回 napi_ok

如果仍然有效,此 API 返回表示與 napi_ref 關聯的 JavaScript 值的 napi_value。否則,result 將為 NULL

當前 Node.js 環境退出時清理#

雖然 Node.js 程序通常在退出時釋放所有資源,但 Node.js 的嵌入者或未來的 Worker 支援可能要求外掛註冊清理鉤子,這些鉤子將在當前 Node.js 環境退出時執行。

Node-API 提供了註冊和登出此類回撥的函式。當這些回撥執行時,外掛持有的所有資源都應被釋放。

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

註冊 fun 作為噹噹前 Node.js 環境退出時,使用 arg 引數執行的函式。

可以安全地多次指定具有不同 arg 值的函式。在這種情況下,它也將被多次呼叫。多次提供相同的 funarg 值是不允許的,會導致程序中止。

鉤子將以相反的順序呼叫,即最近新增的鉤子將首先呼叫。

可以使用 napi_remove_env_cleanup_hook 移除此鉤子。通常,當新增此鉤子的資源被拆除時,就會發生這種情況。

對於非同步清理,可以使用 napi_add_async_cleanup_hook

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

登出 fun 作為噹噹前 Node.js 環境退出時,使用 arg 引數執行的函式。引數和函式值都必須完全匹配。

該函式必須最初透過 napi_add_env_cleanup_hook 註冊,否則程序將中止。

napi_add_async_cleanup_hook#
NAPI_EXTERN napi_status napi_add_async_cleanup_hook(
    node_api_basic_env env,
    napi_async_cleanup_hook hook,
    void* arg,
    napi_async_cleanup_hook_handle* remove_handle); 
  • [in] env: 呼叫 API 的環境。
  • [in] hook: 環境拆除時要呼叫的函式指標。
  • [in] arg: 呼叫 hook 時要傳遞給它的指標。
  • [out] remove_handle: 可選控制代碼,指向非同步清理鉤子。

註冊 hook(型別為 napi_async_cleanup_hook 的函式),作為噹噹前 Node.js 環境退出時,使用 remove_handlearg 引數執行的函式。

napi_add_env_cleanup_hook 不同,該鉤子允許是非同步的。

否則,行為通常與 napi_add_env_cleanup_hook 匹配。

如果 remove_handle 不為 NULL,則會儲存一個不透明值,以後必須將其傳遞給 napi_remove_async_cleanup_hook,無論鉤子是否已被呼叫。通常,當新增此鉤子的資源被拆除時,就會發生這種情況。

napi_remove_async_cleanup_hook#
NAPI_EXTERN napi_status napi_remove_async_cleanup_hook(
    napi_async_cleanup_hook_handle remove_handle); 

登出與 remove_handle 對應的清理鉤子。這將阻止鉤子執行,除非它已經開始執行。對於從 napi_add_async_cleanup_hook 獲取的任何 napi_async_cleanup_hook_handle 值,都必須呼叫此函式。

Node.js 環境退出時的終結#

Node.js 環境可能會在 JavaScript 執行被禁止後儘快在任意時間點被拆除,例如在 worker.terminate() 的請求下。當環境被拆除時,已註冊的 JavaScript 物件的 napi_finalize 回撥、執行緒安全函式和環境例項資料會立即獨立地被呼叫。

napi_finalize 回撥的呼叫安排在手動註冊的清理鉤子之後。為了確保在環境關閉期間外掛終結的正確順序以避免 napi_finalize 回撥中的 use-after-free,外掛應該使用 napi_add_env_cleanup_hooknapi_add_async_cleanup_hook 註冊清理鉤子,以按正確的順序手動釋放分配的資源。

模組註冊#

Node-API 模組的註冊方式與其他模組類似,只是不使用 NODE_MODULE 宏,而是使用以下方式

NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) 

下一個區別是 Init 方法的簽名。對於 Node-API 模組,它如下所示

napi_value Init(napi_env env, napi_value exports); 

Init 的返回值被視為模組的 exports 物件。作為方便,Init 方法透過 exports 引數傳遞一個空物件。如果 Init 返回 NULL,則作為 exports 傳遞的引數由模組匯出。Node-API 模組無法修改 module 物件,但可以將任何內容指定為模組的 exports 屬性。

要將方法 hello 新增為函式,以便可以將其作為外掛提供的方法呼叫

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

要設定一個函式,該函式將由外掛的 require() 返回

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

要定義一個類,以便可以建立新例項(通常與 物件包裝 一起使用)

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

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

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

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

  return exports;
} 

您還可以使用 NAPI_MODULE_INIT 宏,它作為 NAPI_MODULE 和定義 Init 函式的簡寫。

NAPI_MODULE_INIT(/* napi_env env, napi_value exports */) {
  napi_value answer;
  napi_status result;

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

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

  return exports;
} 

引數 envexports 提供給 NAPI_MODULE_INIT 宏的主體。

所有 Node-API 外掛都是上下文感知的,這意味著它們可能會被多次載入。在宣告此類模組時,有一些設計注意事項。上下文感知外掛 文件提供了更多詳細資訊。

在宏呼叫之後,函式體內部將可以使用變數 envexports

有關設定物件屬性的更多詳細資訊,請參閱 使用 JavaScript 屬性 一節。

有關構建外掛模組的更多詳細資訊,請參閱現有 API。

使用 JavaScript 值#

Node-API 公開了一組 API 來建立所有型別的 JavaScript 值。其中一些型別在 ECMAScript 語言規範第語言型別 一節中進行了說明。

從根本上說,這些 API 用於執行以下操作之一

  1. 建立新的 JavaScript 物件
  2. 將原始 C 型別轉換為 Node-API 值
  3. 將 Node-API 值轉換為原始 C 型別
  4. 獲取全域性例項,包括 undefinednull

Node-API 值由型別 napi_value 表示。任何需要 JavaScript 值的 Node-API 呼叫都接受 napi_value。在某些情況下,API 會預先檢查 napi_value 的型別。但是,為了獲得更好的效能,呼叫者最好確保所討論的 napi_value 是 API 期望的 JavaScript 型別。

列舉型別#

napi_key_collection_mode#
typedef enum {
  napi_key_include_prototypes,
  napi_key_own_only
} napi_key_collection_mode; 

描述 Keys/Properties 過濾器列舉

napi_key_collection_mode 限制了收集屬性的範圍。

napi_key_own_only 僅將收集的屬性限制為給定物件。napi_key_include_prototypes 也會包含物件原型鏈中的所有鍵。

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

屬性過濾器位標誌。這與位運算子一起使用以構建複合過濾器。

napi_key_conversion#
typedef enum {
  napi_key_keep_numbers,
  napi_key_numbers_to_strings
} napi_key_conversion; 

napi_key_numbers_to_strings 會將整數索引轉換為字串。napi_key_keep_numbers 會為整數索引返回數字。

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

描述 napi_value 的型別。這通常對應於 ECMAScript 語言規範第語言型別 一節中描述的型別。除了該節中的型別之外,napi_valuetype 還可以表示帶有外部資料的 FunctionObject

型別為 napi_external 的 JavaScript 值在 JavaScript 中表現為普通物件,不能在其上設定任何屬性,也沒有原型。

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

這表示 TypedArray 的底層二進位制標量資料型別。此列舉的元素對應於 ECMAScript 語言規範第 TypedArray 物件 一節。

物件建立函式#

napi_create_array#
napi_status napi_create_array(napi_env env, napi_value* result) 
  • [in] env: 呼叫 Node-API 的環境。
  • [out] result: 表示 JavaScript Arraynapi_value

如果 API 成功,則返回 napi_ok

此 API 返回對應於 JavaScript Array 型別的 Node-API 值。JavaScript 陣列在 ECMAScript 語言規範第 Array 物件 一節中進行了描述。

napi_create_array_with_length#
napi_status napi_create_array_with_length(napi_env env,
                                          size_t length,
                                          napi_value* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] length: Array 的初始長度。
  • [out] result: 表示 JavaScript Arraynapi_value

如果 API 成功,則返回 napi_ok

此 API 返回對應於 JavaScript Array 型別的 Node-API 值。Array 的長度屬性設定為傳入的 length 引數。但是,不保證在建立陣列時 VM 會預分配底層緩衝區。該行為留給底層 VM 實現。如果緩衝區必須是一個可以被 C 直接讀寫 contiguous block of memory,請考慮使用 napi_create_external_arraybuffer

JavaScript 陣列在 ECMAScript 語言規範第 Array 物件 一節中進行了描述。

napi_create_arraybuffer#
napi_status napi_create_arraybuffer(napi_env env,
                                    size_t byte_length,
                                    void** data,
                                    napi_value* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] length: 要建立的陣列緩衝區的長度(以位元組為單位)。
  • [out] data: 指向 ArrayBuffer 底層位元組緩衝區的指標。可以透過傳遞 NULL 來選擇忽略 data
  • [out] result: 表示 JavaScript ArrayBuffernapi_value

如果 API 成功,則返回 napi_ok

此 API 返回對應於 JavaScript ArrayBuffer 的 Node-API 值。ArrayBuffer 用於表示固定長度的二進位制資料緩衝區。它們通常用作 TypedArray 物件的後端緩衝區。分配的 ArrayBuffer 將具有一個底層位元組緩衝區,其大小由傳入的 length 引數確定。如果呼叫者希望直接操作緩衝區,則可選地將底層緩衝區返回給呼叫者。此緩衝區只能從原生程式碼直接寫入。要從 JavaScript 寫入此緩衝區,需要建立型別化陣列或 DataView 物件。

JavaScript ArrayBuffer 物件在 ECMAScript 語言規範第 ArrayBuffer 物件 一節中進行了描述。

napi_create_buffer#
napi_status napi_create_buffer(napi_env env,
                               size_t size,
                               void** data,
                               napi_value* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] size: 底層緩衝區的大小(以位元組為單位)。
  • [out] data: 指向底層緩衝區的原始指標。可以透過傳遞 NULL 來選擇忽略 data
  • [out] result: 表示 node::Buffernapi_value

如果 API 成功,則返回 napi_ok

此 API 分配一個 node::Buffer 物件。雖然這仍然是一個完全支援的資料結構,但在大多數情況下,使用 TypedArray 就足夠了。

napi_create_buffer_copy#
napi_status napi_create_buffer_copy(napi_env env,
                                    size_t length,
                                    const void* data,
                                    void** result_data,
                                    napi_value* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] size: 輸入緩衝區的大小(以位元組為單位)(應與新緩衝區的大小相同)。
  • [in] data: 指向要複製的底層緩衝區的原始指標。
  • [out] result_data: 指向新 Buffer 的底層資料緩衝區的指標。可以透過傳遞 NULL 來選擇忽略 result_data
  • [out] result: 表示 node::Buffernapi_value

如果 API 成功,則返回 napi_ok

此 API 分配一個 node::Buffer 物件,並使用從傳入緩衝區複製的資料對其進行初始化。雖然這仍然是一個完全支援的資料結構,但在大多數情況下,使用 TypedArray 就足夠了。

napi_create_date#
napi_status napi_create_date(napi_env env,
                             double time,
                             napi_value* result); 
  • [in] env: 呼叫 API 的環境。
  • [in] time: ECMAScript 時間值,自 1970 年 1 月 1 日 UTC 起的毫秒數。
  • [out] result: 表示 JavaScript Datenapi_value

如果 API 成功,則返回 napi_ok

此 API 不觀察閏秒;它們被忽略,因為 ECMAScript 與 POSIX 時間規範保持一致。

此 API 分配一個 JavaScript Date 物件。

JavaScript Date 物件在 ECMAScript 語言規範第 Date 物件 一節中進行了描述。

napi_create_external#
napi_status napi_create_external(napi_env env,
                                 void* data,
                                 napi_finalize finalize_cb,
                                 void* finalize_hint,
                                 napi_value* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] data: 指向外部資料的原始指標。
  • [in] finalize_cb: 可選回撥,當外部值被收集時呼叫。napi_finalize 提供了更多詳細資訊。
  • [in] finalize_hint: 在收集期間傳遞給終結回撥的可選提示。
  • [out] result: 表示外部值的 napi_value

如果 API 成功,則返回 napi_ok

此 API 分配一個附加了外部資料的 JavaScript 值。這用於透過 JavaScript 程式碼傳遞外部資料,以便以後可以透過使用 napi_get_value_external 的原生程式碼檢索。

API 添加了一個 napi_finalize 回撥,該回調將在剛剛建立的 JavaScript 物件被垃圾回收時呼叫。

建立的值不是物件,因此不支援額外的屬性。它被認為是一種不同的值型別:使用外部值呼叫 napi_typeof() 會產生 napi_external

napi_create_external_arraybuffer#
napi_status
napi_create_external_arraybuffer(napi_env env,
                                 void* external_data,
                                 size_t byte_length,
                                 napi_finalize finalize_cb,
                                 void* finalize_hint,
                                 napi_value* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] external_data: 指向 ArrayBuffer 底層位元組緩衝區的指標。
  • [in] byte_length: 底層緩衝區的長度(以位元組為單位)。
  • [in] finalize_cb: 可選回撥,當 ArrayBuffer 被收集時呼叫。napi_finalize 提供了更多詳細資訊。
  • [in] finalize_hint: 在收集期間傳遞給終結回撥的可選提示。
  • [out] result: 表示 JavaScript ArrayBuffernapi_value

如果 API 成功,則返回 napi_ok

除了 Node.js 之外的一些執行時已放棄對外部緩衝區的支援。在 Node.js 之外的執行時上,此方法可能返回 napi_no_external_buffers_allowed 以指示不支援外部緩衝區。其中一個執行時是 Electron,如 issue electron/issues/35801 中所述。

為了保持與所有執行時的最廣泛相容性,您可以在包含 node-api 標頭檔案之前在您的外掛中定義 NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED。這樣做將隱藏建立外部緩衝區的兩個函式。這將確保如果您不小心使用了這些方法之一,會發生編譯錯誤。

此 API 返回對應於 JavaScript ArrayBuffer 的 Node-API 值。ArrayBuffer 的底層位元組緩衝區是外部分配和管理的。呼叫者必須確保位元組緩衝區在終結回撥被呼叫之前保持有效。

API 添加了一個 napi_finalize 回撥,該回調將在剛剛建立的 JavaScript 物件被垃圾回收時呼叫。

JavaScript ArrayBufferECMAScript 語言規範第 ArrayBuffer 物件 一節中進行了描述。

napi_create_external_buffer#
napi_status napi_create_external_buffer(napi_env env,
                                        size_t length,
                                        void* data,
                                        napi_finalize finalize_cb,
                                        void* finalize_hint,
                                        napi_value* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] length: 輸入緩衝區的大小(以位元組為單位)(應與新緩衝區的大小相同)。
  • [in] data: 指向要暴露給 JavaScript 的底層緩衝區的原始指標。
  • [in] finalize_cb: 可選回撥,當 ArrayBuffer 被收集時呼叫。napi_finalize 提供了更多詳細資訊。
  • [in] finalize_hint: 在收集期間傳遞給終結回撥的可選提示。
  • [out] result: 表示 node::Buffernapi_value

如果 API 成功,則返回 napi_ok

除了 Node.js 之外的一些執行時已放棄對外部緩衝區的支援。在 Node.js 之外的執行時上,此方法可能返回 napi_no_external_buffers_allowed 以指示不支援外部緩衝區。其中一個執行時是 Electron,如 issue electron/issues/35801 中所述。

為了保持與所有執行時的最廣泛相容性,您可以在包含 node-api 標頭檔案之前在您的外掛中定義 NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED。這樣做將隱藏建立外部緩衝區的兩個函式。這將確保如果您不小心使用了這些方法之一,會發生編譯錯誤。

此 API 分配一個 node::Buffer 物件,並使用傳入緩衝區支援的資料對其進行初始化。雖然這仍然是一個完全支援的資料結構,但在大多數情況下,使用 TypedArray 就足夠了。

API 添加了一個 napi_finalize 回撥,該回調將在剛剛建立的 JavaScript 物件被垃圾回收時呼叫。

對於 Node.js >=4,BuffersUint8Array

napi_create_object#
napi_status napi_create_object(napi_env env, napi_value* result) 
  • [in] env: 呼叫 API 的環境。
  • [out] result: 表示 JavaScript Objectnapi_value

如果 API 成功,則返回 napi_ok

此 API 分配一個預設的 JavaScript Object。它等同於在 JavaScript 中執行 new Object()

JavaScript Object 型別在 ECMAScript 語言規範第 object 型別 一節中進行了描述。

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 語言規範第 symbol 型別 一節中進行了描述。

node_api_symbol_for#
napi_status node_api_symbol_for(napi_env env,
                                const char* utf8description,
                                size_t length,
                                napi_value* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] utf8description: UTF-8 C 字串,表示用作符號描述的文字。
  • [in] length: 描述字串的長度(以位元組為單位),如果為 null 終止,則為 NAPI_AUTO_LENGTH
  • [out] result: 表示 JavaScript symbolnapi_value

如果 API 成功,則返回 napi_ok

此 API 在全域性登錄檔中搜索具有給定描述的現有符號。如果符號已存在,則返回該符號,否則將在登錄檔中建立一個新符號。

JavaScript symbol 型別在 ECMAScript 語言規範第 symbol 型別 一節中進行了描述。

napi_create_typedarray#
napi_status napi_create_typedarray(napi_env env,
                                   napi_typedarray_type type,
                                   size_t length,
                                   napi_value arraybuffer,
                                   size_t byte_offset,
                                   napi_value* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] type: TypedArray 中元素的標量資料型別。
  • [in] length: TypedArray 中的元素數量。
  • [in] arraybuffer: 型別化陣列底層的 ArrayBuffer
  • [in] byte_offset: ArrayBuffer 中開始投影 TypedArray 的位元組偏移量。
  • [out] result: 表示 JavaScript TypedArraynapi_value

如果 API 成功,則返回 napi_ok

此 API 在現有 ArrayBuffer 上建立 JavaScript TypedArray 物件。TypedArray 物件提供了一個類似陣列的檢視,位於底層資料緩衝區之上,其中每個元素都具有相同的底層二進位制標量資料型別。

要求 (length * size_of_element) + byte_offset 應該小於或等於傳入陣列的位元組大小。如果不是,則會引發 RangeError 異常。

JavaScript TypedArray 物件在 ECMAScript 語言規範第 TypedArray 物件 一節中進行了描述。

node_api_create_buffer_from_arraybuffer#
napi_status NAPI_CDECL node_api_create_buffer_from_arraybuffer(napi_env env,
                                                              napi_value arraybuffer,
                                                              size_t byte_offset,
                                                              size_t byte_length,
                                                              napi_value* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] arraybuffer: 將從中建立緩衝區的 ArrayBuffer
  • [in] byte_offset: ArrayBuffer 中開始建立緩衝區的位元組偏移量。
  • [in] byte_length: 將從 ArrayBuffer 建立的緩衝區的長度(以位元組為單位)。
  • [out] result: 表示建立的 JavaScript Buffer 物件的 napi_value

如果 API 成功,則返回 napi_ok

此 API 從現有 ArrayBuffer 建立 JavaScript Buffer 物件。Buffer 物件是 Node.js 特有的類,它提供了一種直接在 JavaScript 中處理二進位制資料的方法。

位元組範圍 [byte_offset, byte_offset + byte_length) 必須在 ArrayBuffer 的邊界內。如果 byte_offset + byte_length 超過 ArrayBuffer 的大小,則會引發 RangeError 異常。

napi_create_dataview#
napi_status napi_create_dataview(napi_env env,
                                 size_t byte_length,
                                 napi_value arraybuffer,
                                 size_t byte_offset,
                                 napi_value* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] length: DataView 中的元素數量。
  • [in] arraybuffer: DataView 底層的 ArrayBuffer
  • [in] byte_offset: ArrayBuffer 中開始投影 DataView 的位元組偏移量。
  • [out] result: 表示 JavaScript DataViewnapi_value

如果 API 成功,則返回 napi_ok

此 API 在現有 ArrayBuffer 上建立 JavaScript DataView 物件。DataView 物件提供了一個類似陣列的檢視,位於底層資料緩衝區之上,但允許 ArrayBuffer 中具有不同大小和型別的項。

要求 byte_length + byte_offset 小於或等於傳入陣列的位元組大小。如果不是,則會引發 RangeError 異常。

JavaScript DataView 物件在 ECMAScript 語言規範第 DataView 物件 一節中進行了描述。

將 C 型別轉換為 Node-API 的函式#

napi_create_int32#
napi_status napi_create_int32(napi_env env, int32_t value, napi_value* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 要在 JavaScript 中表示的整數值。
  • [out] result: 表示 JavaScript numbernapi_value

如果 API 成功,則返回 napi_ok

此 API 用於將 C int32_t 型別轉換為 JavaScript number 型別。

JavaScript number 型別在 ECMAScript 語言規範第 number 型別 一節中進行了描述。

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 語言規範第 number 型別 一節中進行了描述。

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 語言規範第 number 型別 一節中進行了描述。請注意,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 語言規範第 number 型別 一節中進行了描述。

napi_create_bigint_int64#
napi_status napi_create_bigint_int64(napi_env env,
                                     int64_t value,
                                     napi_value* result); 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 要在 JavaScript 中表示的整數值。
  • [out] result: 表示 JavaScript BigIntnapi_value

如果 API 成功,則返回 napi_ok

此 API 將 C int64_t 型別轉換為 JavaScript BigInt 型別。

napi_create_bigint_uint64#
napi_status napi_create_bigint_uint64(napi_env env,
                                      uint64_t value,
                                      napi_value* result); 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 要在 JavaScript 中表示的無符號整數值。
  • [out] result: 表示 JavaScript BigIntnapi_value

如果 API 成功,則返回 napi_ok

此 API 將 C uint64_t 型別轉換為 JavaScript BigInt 型別。

napi_create_bigint_words#
napi_status napi_create_bigint_words(napi_env env,
                                     int sign_bit,
                                     size_t word_count,
                                     const uint64_t* words,
                                     napi_value* result); 
  • [in] env: 呼叫 API 的環境。
  • [in] sign_bit: 確定結果 BigInt 是正數還是負數。
  • [in] word_count: words 陣列的長度。
  • [in] words: uint64_t 小端 64 位字的陣列。
  • [out] result: 表示 JavaScript BigIntnapi_value

如果 API 成功,則返回 napi_ok

此 API 將無符號 64 位字陣列轉換為單個 BigInt 值。

結果 BigInt 計算為: (–1)sign_bit (words[0] × (264)0 + words[1] × (264)1 + …)

napi_create_string_latin1#
napi_status napi_create_string_latin1(napi_env env,
                                      const char* str,
                                      size_t length,
                                      napi_value* result); 
  • [in] env: 呼叫 API 的環境。
  • [in] str: 表示 ISO-8859-1 編碼字串的字元緩衝區。
  • [in] length: 字串的長度(以位元組為單位),如果為 null 終止,則為 NAPI_AUTO_LENGTH
  • [out] result: 表示 JavaScript stringnapi_value

如果 API 成功,則返回 napi_ok

此 API 從 ISO-8859-1 編碼的 C 字串建立 JavaScript string 值。原生字串被複制。

JavaScript string 型別在 ECMAScript 語言規範第 string 型別 一節中進行了描述。

node_api_create_external_string_latin1#
napi_status
node_api_create_external_string_latin1(napi_env env,
                                       char* str,
                                       size_t length,
                                       napi_finalize finalize_callback,
                                       void* finalize_hint,
                                       napi_value* result,
                                       bool* copied); 
  • [in] env: 呼叫 API 的環境。
  • [in] str: 表示 ISO-8859-1 編碼字串的字元緩衝區。
  • [in] length: 字串的長度(以位元組為單位),如果為 null 終止,則為 NAPI_AUTO_LENGTH
  • [in] finalize_callback: 當字串被收集時要呼叫的函式。該函式將使用以下引數呼叫
    • [in] env: 外掛執行的環境。如果字串作為 worker 或主 Node.js 例項終止的一部分而被收集,則此值可能為 null。
    • [in] data: 這是 str 的值,作為 void* 指標。
    • [in] finalize_hint: 這是提供給 API 的 finalize_hint 值。napi_finalize 提供了更多詳細資訊。此引數是可選的。傳遞空值意味著當相應的 JavaScript 字串被收集時,外掛不需要收到通知。
  • [in] finalize_hint: 在收集期間傳遞給終結回撥的可選提示。
  • [out] result: 表示 JavaScript stringnapi_value
  • [out] copied: 字串是否被複制。如果已複製,則終結器將已呼叫以銷燬 str

如果 API 成功,則返回 napi_ok

此 API 從 ISO-8859-1 編碼的 C 字串建立 JavaScript string 值。原生字串可能未被複制,因此必須在 JavaScript 值的整個生命週期中存在。

JavaScript string 型別在 ECMAScript 語言規範第 string 型別 一節中進行了描述。

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 語言規範第 string 型別 一節中進行了描述。

node_api_create_external_string_utf16#
napi_status
node_api_create_external_string_utf16(napi_env env,
                                      char16_t* str,
                                      size_t length,
                                      napi_finalize finalize_callback,
                                      void* finalize_hint,
                                      napi_value* result,
                                      bool* copied); 
  • [in] env: 呼叫 API 的環境。
  • [in] str: 表示 UTF16-LE 編碼字串的字元緩衝區。
  • [in] length: 字串的長度(以雙位元組程式碼單元為單位),如果為 null 終止,則為 NAPI_AUTO_LENGTH
  • [in] finalize_callback: 當字串被收集時要呼叫的函式。該函式將使用以下引數呼叫
    • [in] env: 外掛執行的環境。如果字串作為 worker 或主 Node.js 例項終止的一部分而被收集,則此值可能為 null。
    • [in] data: 這是 str 的值,作為 void* 指標。
    • [in] finalize_hint: 這是提供給 API 的 finalize_hint 值。napi_finalize 提供了更多詳細資訊。此引數是可選的。傳遞空值意味著當相應的 JavaScript 字串被收集時,外掛不需要收到通知。
  • [in] finalize_hint: 在收集期間傳遞給終結回撥的可選提示。
  • [out] result: 表示 JavaScript stringnapi_value
  • [out] copied: 字串是否被複制。如果已複製,則終結器將已呼叫以銷燬 str

如果 API 成功,則返回 napi_ok

此 API 從 UTF16-LE 編碼的 C 字串建立 JavaScript string 值。原生字串可能未被複制,因此必須在 JavaScript 值的整個生命週期中存在。

JavaScript string 型別在 ECMAScript 語言規範第 string 型別 一節中進行了描述。

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 語言規範第 string 型別 一節中進行了描述。

建立最佳化屬性鍵的函式#

包括 V8 在內的許多 JavaScript 引擎都使用內部化字串作為鍵來設定和獲取屬性值。它們通常使用雜湊表來建立和查詢此類字串。雖然每個鍵建立會增加一些成本,但之後透過啟用字串指標而不是整個字串的比較來提高效能。

如果打算將新的 JavaScript 字串用作屬性鍵,那麼對於某些 JavaScript 引擎,使用本節中的函式會更有效。否則,請使用 napi_create_string_utf8node_api_create_external_string_utf8 系列函式,因為使用屬性鍵建立方法建立/儲存字串可能會產生額外的開銷。

node_api_create_property_key_latin1#
napi_status NAPI_CDECL node_api_create_property_key_latin1(napi_env env,
                                                           const char* str,
                                                           size_t length,
                                                           napi_value* result); 
  • [in] env: 呼叫 API 的環境。
  • [in] str: 表示 ISO-8859-1 編碼字串的字元緩衝區。
  • [in] length: 字串的長度(以位元組為單位),如果為 null 終止,則為 NAPI_AUTO_LENGTH
  • [out] result: 表示最佳化 JavaScript stringnapi_value,用作物件的屬性鍵。

如果 API 成功,則返回 napi_ok

此 API 從 ISO-8859-1 編碼的 C 字串建立最佳化 JavaScript string 值,用作物件的屬性鍵。原生字串被複制。與 napi_create_string_latin1 不同,隨後使用相同的 str 指標呼叫此函式可能會從所請求的 napi_value 的建立中受益於加速,具體取決於引擎。

JavaScript string 型別在 ECMAScript 語言規範第 string 型別 一節中進行了描述。

node_api_create_property_key_utf16#
napi_status NAPI_CDECL node_api_create_property_key_utf16(napi_env env,
                                                          const char16_t* str,
                                                          size_t length,
                                                          napi_value* result); 
  • [in] env: 呼叫 API 的環境。
  • [in] str: 表示 UTF16-LE 編碼字串的字元緩衝區。
  • [in] length: 字串的長度(以雙位元組程式碼單元為單位),如果為 null 終止,則為 NAPI_AUTO_LENGTH
  • [out] result: 表示最佳化 JavaScript stringnapi_value,用作物件的屬性鍵。

如果 API 成功,則返回 napi_ok

此 API 從 UTF16-LE 編碼的 C 字串建立最佳化 JavaScript string 值,用作物件的屬性鍵。原生字串被複制。

JavaScript string 型別在 ECMAScript 語言規範第 string 型別 一節中進行了描述。

node_api_create_property_key_utf8#
napi_status NAPI_CDECL node_api_create_property_key_utf8(napi_env env,
                                                         const char* str,
                                                         size_t length,
                                                         napi_value* result); 
  • [in] env: 呼叫 API 的環境。
  • [in] str: 表示 UTF8 編碼字串的字元緩衝區。
  • [in] length: 字串的長度(以雙位元組程式碼單元為單位),如果為 null 終止,則為 NAPI_AUTO_LENGTH
  • [out] result: 表示最佳化 JavaScript stringnapi_value,用作物件的屬性鍵。

如果 API 成功,則返回 napi_ok

此 API 從 UTF8 編碼的 C 字串建立最佳化 JavaScript string 值,用作物件的屬性鍵。原生字串被複制。

JavaScript string 型別在 ECMAScript 語言規範第 string 型別 一節中進行了描述。

將 Node-API 轉換為 C 型別的函式#

napi_get_array_length#
napi_status napi_get_array_length(napi_env env,
                                  napi_value value,
                                  uint32_t* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 表示正在查詢長度的 JavaScript Arraynapi_value
  • [out] result: 表示陣列長度的 uint32

如果 API 成功,則返回 napi_ok

此 API 返回陣列的長度。

Array 長度在 ECMAScript 語言規範第 Array 例項長度 一節中進行了描述。

napi_get_arraybuffer_info#
napi_status napi_get_arraybuffer_info(napi_env env,
                                      napi_value arraybuffer,
                                      void** data,
                                      size_t* byte_length) 
  • [in] env: 呼叫 API 的環境。
  • [in] arraybuffer: 表示正在查詢的 ArrayBufferSharedArrayBuffernapi_value
  • [out] data: ArrayBufferSharedArrayBuffer 的底層資料緩衝區為 0,這可以是 NULL 或任何其他指標值。
  • [out] byte_length: 底層資料緩衝區的長度(以位元組為單位)。

如果 API 成功,則返回 napi_ok

此 API 用於檢索 ArrayBufferSharedArrayBuffer 的底層資料緩衝區及其長度。

警告: 使用此 API 時請務必小心。底層資料緩衝區的生命週期由 ArrayBufferSharedArrayBuffer 管理,即使在返回後也是如此。使用此 API 的一種可能的安全方法是結合 napi_create_reference 使用,該方法可用於保證對 ArrayBufferSharedArrayBuffer 生命週期的控制。只要沒有呼叫可能觸發 GC 的其他 API,在同一回撥中使用返回的資料緩衝區也是安全的。

napi_get_buffer_info#
napi_status napi_get_buffer_info(napi_env env,
                                 napi_value value,
                                 void** data,
                                 size_t* length) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 表示正在查詢的 node::BufferUint8Arraynapi_value
  • [out] data: node::BufferUint8Array 的底層資料緩衝區。如果長度為 0,這可以是 NULL 或任何其他指標值。
  • [out] length: 底層資料緩衝區的長度(以位元組為單位)。

如果 API 成功,則返回 napi_ok

此方法返回與 napi_get_typedarray_info 相同的 databyte_length。並且 napi_get_typedarray_info 也接受 node::Buffer (一個 Uint8Array) 作為值。

此 API 用於檢索 node::Buffer 的底層資料緩衝區及其長度。

警告: 使用此 API 時請務必小心,因為如果底層資料緩衝區由 VM 管理,則其生命週期無法保證。

napi_get_prototype#
napi_status napi_get_prototype(napi_env env,
                               napi_value object,
                               napi_value* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] object: 表示要返回其原型的 JavaScript Objectnapi_value。這返回與 Object.getPrototypeOf 等效的值(與函式的 prototype 屬性不同)。
  • [out] result: 表示給定物件原型的 napi_value

如果 API 成功,則返回 napi_ok

napi_get_typedarray_info#
napi_status napi_get_typedarray_info(napi_env env,
                                     napi_value typedarray,
                                     napi_typedarray_type* type,
                                     size_t* length,
                                     void** data,
                                     napi_value* arraybuffer,
                                     size_t* byte_offset) 
  • [in] env: 呼叫 API 的環境。
  • [in] typedarray: 表示要查詢其屬性的 TypedArraynapi_value
  • [out] type: TypedArray 中元素的標量資料型別。
  • [out] length: TypedArray 中的元素數量。
  • [out] data: TypedArray 的底層資料緩衝區,已透過 byte_offset 值調整,使其指向 TypedArray 中的第一個元素。如果陣列長度為 0,則此值可能為 NULL 或任何其他指標值。
  • [out] arraybuffer: TypedArray 底層的 ArrayBuffer
  • [out] byte_offset: 底層原生陣列中第一個元素所在位置的位元組偏移量。資料引數的值已經過調整,因此資料指向陣列中的第一個元素。因此,原生陣列的第一個位元組將位於 data - byte_offset

如果 API 成功,則返回 napi_ok

此 API 返回型別化陣列的各種屬性。

如果不需要某個屬性,則任何輸出引數都可以是 NULL

警告: 使用此 API 時請務必小心,因為底層資料緩衝區由 VM 管理。

napi_get_dataview_info#
napi_status napi_get_dataview_info(napi_env env,
                                   napi_value dataview,
                                   size_t* byte_length,
                                   void** data,
                                   napi_value* arraybuffer,
                                   size_t* byte_offset) 
  • [in] env: 呼叫 API 的環境。
  • [in] dataview: 表示要查詢其屬性的 DataViewnapi_value
  • [out] byte_length: DataView 中的位元組數。
  • [out] data: DataView 的底層資料緩衝區。如果 byte_length 為 0,則此值可能為 NULL 或任何其他指標值。
  • [out] arraybuffer: DataView 底層的 ArrayBuffer
  • [out] byte_offset: 資料緩衝區中開始投影 DataView 的位元組偏移量。

如果 API 成功,則返回 napi_ok

如果不需要某個屬性,則任何輸出引數都可以是 NULL

此 API 返回 DataView 的各種屬性。

napi_get_date_value#
napi_status napi_get_date_value(napi_env env,
                                napi_value value,
                                double* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 表示 JavaScript Datenapi_value
  • [out] result: 時間值,表示自 1970 年 1 月 1 日 UTC 午夜以來的毫秒數,以 double 表示。

此 API 不觀察閏秒;它們被忽略,因為 ECMAScript 與 POSIX 時間規範保持一致。

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

此 API 返回給定 JavaScript Date 的時間值的 C 雙精度原始值。

napi_get_value_bool#
napi_status napi_get_value_bool(napi_env env, napi_value value, bool* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 表示 JavaScript Booleannapi_value
  • [out] result: 給定 JavaScript Boolean 的 C 布林原始等效值。

如果 API 成功,則返回 napi_ok。如果傳入非布林 napi_value,則返回 napi_boolean_expected

此 API 返回給定 JavaScript Boolean 的 C 布林原始等效值。

napi_get_value_double#
napi_status napi_get_value_double(napi_env env,
                                  napi_value value,
                                  double* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 表示 JavaScript numbernapi_value
  • [out] result: 給定 JavaScript number 的 C 雙精度原始等效值。

如果 API 成功,則返回 napi_ok。如果傳入非數字 napi_value,則返回 napi_number_expected

此 API 返回給定 JavaScript number 的 C 雙精度原始等效值。

napi_get_value_bigint_int64#
napi_status napi_get_value_bigint_int64(napi_env env,
                                        napi_value value,
                                        int64_t* result,
                                        bool* lossless); 
  • [in] env: 呼叫 API 的環境
  • [in] value: 表示 JavaScript BigIntnapi_value
  • [out] result: 給定 JavaScript BigInt 的 C int64_t 原始等效值。
  • [out] lossless: 指示 BigInt 值是否無損轉換。

如果 API 成功,則返回 napi_ok。如果傳入非 BigInt,則返回 napi_bigint_expected

此 API 返回給定 JavaScript BigInt 的 C int64_t 原始等效值。如果需要,它將截斷該值,並將 lossless 設定為 false

napi_get_value_bigint_uint64#
napi_status napi_get_value_bigint_uint64(napi_env env,
                                        napi_value value,
                                        uint64_t* result,
                                        bool* lossless); 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 表示 JavaScript BigIntnapi_value
  • [out] result: 給定 JavaScript BigInt 的 C uint64_t 原始等效值。
  • [out] lossless: 指示 BigInt 值是否無損轉換。

如果 API 成功,則返回 napi_ok。如果傳入非 BigInt,則返回 napi_bigint_expected

此 API 返回給定 JavaScript BigInt 的 C uint64_t 原始等效值。如果需要,它將截斷該值,並將 lossless 設定為 false

napi_get_value_bigint_words#
napi_status napi_get_value_bigint_words(napi_env env,
                                        napi_value value,
                                        int* sign_bit,
                                        size_t* word_count,
                                        uint64_t* words); 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 表示 JavaScript BigIntnapi_value
  • [out] sign_bit: 表示 JavaScript BigInt 是正數還是負數的整數。
  • [in/out] word_count: 必須初始化為 words 陣列的長度。返回時,它將設定為儲存此 BigInt 所需的實際字數。
  • [out] words: 指向預分配的 64 位字陣列的指標。

如果 API 成功,則返回 napi_ok

此 API 將單個 BigInt 值轉換為符號位、64 位小端陣列以及陣列中的元素數量。sign_bitwords 都可以設定為 NULL,以便只獲取 word_count

napi_get_value_external#
napi_status napi_get_value_external(napi_env env,
                                    napi_value value,
                                    void** result) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 表示 JavaScript 外部值的 napi_value
  • [out] result: 指向 JavaScript 外部值包裝的資料的指標。

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

此 API 檢索先前傳遞給 napi_create_external() 的外部資料指標。

napi_get_value_int32#
napi_status napi_get_value_int32(napi_env env,
                                 napi_value value,
                                 int32_t* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 表示 JavaScript numbernapi_value
  • [out] result: 給定 JavaScript number 的 C int32 原始等效值。

如果 API 成功,則返回 napi_ok。如果傳入非數字 napi_value,則返回 napi_number_expected

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

如果數字超出 32 位整數的範圍,則結果將被截斷為等效的低 32 位。如果值大於 231 - 1,這可能導致較大的正數變為負數。

非有限數字值(NaN+Infinity-Infinity)將結果設定為零。

napi_get_value_int64#
napi_status napi_get_value_int64(napi_env env,
                                 napi_value value,
                                 int64_t* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 表示 JavaScript numbernapi_value
  • [out] result: 給定 JavaScript number 的 C int64 原始等效值。

如果 API 成功,則返回 napi_ok。如果傳入非數字 napi_value,則返回 napi_number_expected

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

超出 Number.MIN_SAFE_INTEGER -(2**53 - 1) - Number.MAX_SAFE_INTEGER (2**53 - 1) 範圍的 number 值將失去精度。

非有限數字值(NaN+Infinity-Infinity)將結果設定為零。

napi_get_value_string_latin1#
napi_status napi_get_value_string_latin1(napi_env env,
                                         napi_value value,
                                         char* buf,
                                         size_t bufsize,
                                         size_t* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 表示 JavaScript 字串的 napi_value
  • [in] buf: 寫入 ISO-8859-1 編碼字串的緩衝區。如果傳入 NULL,則字串的長度(以位元組為單位,不包括空終止符)將在 result 中返回。
  • [in] bufsize: 目標緩衝區的大小。當此值不足時,返回的字串將被截斷並以空終止。如果此值為零,則不返回字串,並且不對緩衝區進行任何更改。
  • [out] result: 複製到緩衝區中的位元組數,不包括空終止符。

如果 API 成功,則返回 napi_ok。如果傳入非 string napi_value,則返回 napi_string_expected

此 API 返回與傳入值對應的 ISO-8859-1 編碼字串。

napi_get_value_string_utf8#
napi_status napi_get_value_string_utf8(napi_env env,
                                       napi_value value,
                                       char* buf,
                                       size_t bufsize,
                                       size_t* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 表示 JavaScript 字串的 napi_value
  • [in] buf: 寫入 UTF8 編碼字串的緩衝區。如果傳入 NULL,則字串的長度(以位元組為單位,不包括空終止符)將在 result 中返回。
  • [in] bufsize: 目標緩衝區的大小。當此值不足時,返回的字串將被截斷並以空終止。如果此值為零,則不返回字串,並且不對緩衝區進行任何更改。
  • [out] result: 複製到緩衝區中的位元組數,不包括空終止符。

如果 API 成功,則返回 napi_ok。如果傳入非 string napi_value,則返回 napi_string_expected

此 API 返回與傳入值對應的 UTF8 編碼字串。

napi_get_value_string_utf16#
napi_status napi_get_value_string_utf16(napi_env env,
                                        napi_value value,
                                        char16_t* buf,
                                        size_t bufsize,
                                        size_t* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 表示 JavaScript 字串的 napi_value
  • [in] buf: 寫入 UTF16-LE 編碼字串的緩衝區。如果傳入 NULL,則字串的長度(以 2 位元組程式碼單元為單位,不包括空終止符)將返回。
  • [in] bufsize: 目標緩衝區的大小。當此值不足時,返回的字串將被截斷並以空終止。如果此值為零,則不返回字串,並且不對緩衝區進行任何更改。
  • [out] result: 複製到緩衝區中的 2 位元組程式碼單元數,不包括空終止符。

如果 API 成功,則返回 napi_ok。如果傳入非 string napi_value,則返回 napi_string_expected

此 API 返回與傳入值對應的 UTF16 編碼字串。

napi_get_value_uint32#
napi_status napi_get_value_uint32(napi_env env,
                                  napi_value value,
                                  uint32_t* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 表示 JavaScript numbernapi_value
  • [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] result: 表示要檢索的 JavaScript Boolean 單例的 napi_value

如果 API 成功,則返回 napi_ok

此 API 用於返回用於表示給定布林值的 JavaScript 單例物件。

napi_get_global#
napi_status napi_get_global(napi_env env, napi_value* result) 
  • [in] env: 呼叫 API 的環境。
  • [out] result: 表示 JavaScript global 物件的 napi_value

如果 API 成功,則返回 napi_ok

此 API 返回 global 物件。

napi_get_null#
napi_status napi_get_null(napi_env env, napi_value* result) 
  • [in] env: 呼叫 API 的環境。
  • [out] result: 表示 JavaScript null 物件的 napi_value

如果 API 成功,則返回 napi_ok

此 API 返回 null 物件。

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

如果 API 成功,則返回 napi_ok

此 API 返回 Undefined 物件。

使用 JavaScript 值和抽象操作#

Node-API 公開了一組 API 來對 JavaScript 值執行一些抽象操作。

這些 API 支援執行以下操作之一

  1. 將 JavaScript 值強制轉換為特定的 JavaScript 型別(例如 numberstring)。
  2. 檢查 JavaScript 值的型別。
  3. 檢查兩個 JavaScript 值之間的相等性。

napi_coerce_to_bool#

napi_status napi_coerce_to_bool(napi_env env,
                                napi_value value,
                                napi_value* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 要強制轉換的 JavaScript 值。
  • [out] result: 表示強制轉換的 JavaScript Booleannapi_value

如果 API 成功,則返回 napi_ok

此 API 實現了 ECMAScript 語言規範第 ToBoolean 一節中定義的抽象操作 ToBoolean()

napi_coerce_to_number#

napi_status napi_coerce_to_number(napi_env env,
                                  napi_value value,
                                  napi_value* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 要強制轉換的 JavaScript 值。
  • [out] result: 表示強制轉換的 JavaScript numbernapi_value

如果 API 成功,則返回 napi_ok

此 API 實現了 ECMAScript 語言規範第 ToNumber 一節中定義的抽象操作 ToNumber()。如果傳入的值是物件,此函式可能會執行 JS 程式碼。

napi_coerce_to_object#

napi_status napi_coerce_to_object(napi_env env,
                                  napi_value value,
                                  napi_value* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 要強制轉換的 JavaScript 值。
  • [out] result: 表示強制轉換的 JavaScript Objectnapi_value

如果 API 成功,則返回 napi_ok

此 API 實現了 ECMAScript 語言規範第 ToObject 一節中定義的抽象操作 ToObject()

napi_coerce_to_string#

napi_status napi_coerce_to_string(napi_env env,
                                  napi_value value,
                                  napi_value* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 要強制轉換的 JavaScript 值。
  • [out] result: 表示強制轉換的 JavaScript stringnapi_value

如果 API 成功,則返回 napi_ok

此 API 實現了 ECMAScript 語言規範第 ToString 一節中定義的抽象操作 ToString()。如果傳入的值是物件,此函式可能會執行 JS 程式碼。

napi_typeof#

napi_status napi_typeof(napi_env env, napi_value value, napi_valuetype* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 要查詢其型別的 JavaScript 值。
  • [out] result: JavaScript 值的型別。

如果 API 成功,則返回 napi_ok

  • 如果 value 的型別不是已知的 ECMAScript 型別且 value 不是外部值,則返回 napi_invalid_arg

此 API 表示類似於在 ECMAScript 語言規範第 typeof 運算子 一節中定義的對物件呼叫 typeof 運算子的行為。但是,有一些差異

  1. 它支援檢測外部值。
  2. 它將 null 檢測為單獨的型別,而 ECMAScript typeof 會檢測 object

如果 value 的型別無效,則返回錯誤。

napi_instanceof#

napi_status napi_instanceof(napi_env env,
                            napi_value object,
                            napi_value constructor,
                            bool* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] object: 要檢查的 JavaScript 值。
  • [in] constructor: 要檢查的建構函式的 JavaScript 函式物件。
  • [out] result: 如果 object instanceof constructor 為 true,則設定為 true 的布林值。

如果 API 成功,則返回 napi_ok

此 API 表示在 ECMAScript 語言規範第 instanceof 運算子 一節中定義的對物件呼叫 instanceof 運算子的行為。

napi_is_array#

napi_status napi_is_array(napi_env env, napi_value value, bool* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 要檢查的 JavaScript 值。
  • [out] result: 給定物件是否為陣列。

如果 API 成功,則返回 napi_ok

此 API 表示在 ECMAScript 語言規範第 IsArray 一節中定義的對物件呼叫 IsArray 操作的行為。

napi_is_arraybuffer#

napi_status napi_is_arraybuffer(napi_env env, napi_value value, bool* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 要檢查的 JavaScript 值。
  • [out] result: 給定物件是否為 ArrayBuffer

如果 API 成功,則返回 napi_ok

此 API 檢查傳入的 Object 是否為陣列緩衝區。

napi_is_buffer#

napi_status napi_is_buffer(napi_env env, napi_value value, bool* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 要檢查的 JavaScript 值。
  • [out] result: 給定的 napi_value 是否表示 node::BufferUint8Array 物件。

如果 API 成功,則返回 napi_ok

此 API 檢查傳入的 Object 是否為緩衝區或 Uint8Array。如果呼叫者需要檢查值是否為 Uint8Array,則應優先使用 napi_is_typedarray

napi_is_date#

napi_status napi_is_date(napi_env env, napi_value value, bool* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 要檢查的 JavaScript 值。
  • [out] result: 給定的 napi_value 是否表示 JavaScript Date 物件。

如果 API 成功,則返回 napi_ok

此 API 檢查傳入的 Object 是否為日期。

napi_is_error#

napi_status napi_is_error(napi_env env, napi_value value, bool* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 要檢查的 JavaScript 值。
  • [out] result: 給定的 napi_value 是否表示 Error 物件。

如果 API 成功,則返回 napi_ok

此 API 檢查傳入的 Object 是否為 Error

napi_is_typedarray#

napi_status napi_is_typedarray(napi_env env, napi_value value, bool* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 要檢查的 JavaScript 值。
  • [out] result: 給定的 napi_value 是否表示 TypedArray

如果 API 成功,則返回 napi_ok

此 API 檢查傳入的 Object 是否為型別化陣列。

napi_is_dataview#

napi_status napi_is_dataview(napi_env env, napi_value value, bool* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 要檢查的 JavaScript 值。
  • [out] result: 給定的 napi_value 是否表示 DataView

如果 API 成功,則返回 napi_ok

此 API 檢查傳入的 Object 是否為 DataView

napi_strict_equals#

napi_status napi_strict_equals(napi_env env,
                               napi_value lhs,
                               napi_value rhs,
                               bool* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] lhs: 要檢查的 JavaScript 值。
  • [in] rhs: 要檢查的 JavaScript 值。
  • [out] result: 兩個 napi_value 物件是否相等。

如果 API 成功,則返回 napi_ok

此 API 表示 ECMAScript 語言規範第 IsStrctEqual 一節中定義的嚴格相等演算法的呼叫。

napi_detach_arraybuffer#

napi_status napi_detach_arraybuffer(napi_env env,
                                    napi_value arraybuffer) 
  • [in] env: 呼叫 API 的環境。
  • [in] arraybuffer: 要分離的 JavaScript ArrayBuffer

如果 API 成功,則返回 napi_ok。如果傳入不可分離的 ArrayBuffer,則返回 napi_detachable_arraybuffer_expected

通常,如果 ArrayBuffer 之前已被分離,則它是不可分離的。引擎可能會對 ArrayBuffer 是否可分離施加額外的條件。例如,V8 要求 ArrayBuffer 必須是外部的,即使用 napi_create_external_arraybuffer 建立的。

此 API 表示在 ECMAScript 語言規範第 detachArrayBuffer 一節中定義的 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] result: arraybuffer 是否已分離。

如果 API 成功,則返回 napi_ok

如果 ArrayBuffer 的內部資料為 null,則認為它已分離。

此 API 表示在 ECMAScript 語言規範第 isDetachedBuffer 一節中定義的 ArrayBuffer IsDetachedBuffer 操作的呼叫。

node_api_is_sharedarraybuffer#

穩定性:1 - 實驗性

napi_status node_api_is_sharedarraybuffer(napi_env env, napi_value value, bool* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] value: 要檢查的 JavaScript 值。
  • [out] result: 給定的 napi_value 是否表示 SharedArrayBuffer

如果 API 成功,則返回 napi_ok

此 API 檢查傳入的 Object 是否為 SharedArrayBuffer

node_api_create_sharedarraybuffer#

穩定性:1 - 實驗性

napi_status node_api_create_sharedarraybuffer(napi_env env,
                                             size_t byte_length,
                                             void** data,
                                             napi_value* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] byte_length: 要建立的共享陣列緩衝區的長度(以位元組為單位)。
  • [out] data: 指向 SharedArrayBuffer 底層位元組緩衝區的指標。可以透過傳遞 NULL 來選擇忽略 data
  • [out] result: 表示 JavaScript SharedArrayBuffernapi_value

如果 API 成功,則返回 napi_ok

此 API 返回對應於 JavaScript SharedArrayBuffer 的 Node-API 值。SharedArrayBuffer 用於表示固定長度的二進位制資料緩衝區,可以在多個 worker 之間共享。

分配的 SharedArrayBuffer 將具有一個底層位元組緩衝區,其大小由傳入的 byte_length 引數確定。如果呼叫者希望直接操作緩衝區,則可選地將底層緩衝區返回給呼叫者。此緩衝區只能從原生程式碼直接寫入。要從 JavaScript 寫入此緩衝區,需要建立型別化陣列或 DataView 物件。

JavaScript SharedArrayBuffer 物件在 ECMAScript 語言規範第 SharedArrayBuffer 物件 一節中進行了描述。

使用 JavaScript 屬性#

Node-API 公開了一組 API 來獲取和設定 JavaScript 物件的屬性。

JavaScript 中的屬性表示為鍵和值的元組。從根本上說,Node-API 中的所有屬性鍵都可以以下列形式之一表示

  • 命名:一個簡單的 UTF8 編碼字串
  • 整數索引:一個由 uint32_t 表示的索引值
  • JavaScript 值:這些在 Node-API 中由 napi_value 表示。這可以是一個表示 stringnumbersymbolnapi_value

Node-API 值由型別 napi_value 表示。任何需要 JavaScript 值的 Node-API 呼叫都接受 napi_value。但是,呼叫者有責任確保所討論的 napi_value 是 API 期望的 JavaScript 型別。

本節中記錄的 API 提供了一個簡單的介面來獲取和設定由 napi_value 表示的任意 JavaScript 物件的屬性。

例如,考慮以下 JavaScript 程式碼片段

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

可以使用 Node-API 值透過以下片段完成等效操作

napi_status status = napi_generic_failure;

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

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

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

可以以類似的方式設定索引屬性。考慮以下 JavaScript 片段

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

可以使用 Node-API 值透過以下片段完成等效操作

napi_status status = napi_generic_failure;

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

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

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

可以使用本節中描述的 API 檢索屬性。考慮以下 JavaScript 片段

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

以下是 Node-API 對應物的近似等效項

napi_status status = napi_generic_failure;

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

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

最後,出於效能原因,也可以在一個物件上定義多個屬性。考慮以下 JavaScript

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

以下是 Node-API 對應物的近似等效項

napi_status status = napi_status_generic_failure;

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

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

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

結構體#

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

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

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

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

napi_property_attributes 是用於控制 JavaScript 物件上設定屬性行為的位標誌。除了 napi_static 之外,它們對應於 ECMAScript 語言規範第 property attributes 一節中列出的屬性。它們可以是一個或多個以下位標誌

  • napi_default: 屬性上未設定顯式屬性。預設情況下,屬性是隻讀的,不可列舉且不可配置。
  • napi_writable: 屬性是可寫的。
  • napi_enumerable: 屬性是可列舉的。
  • napi_configurable: 屬性是可配置的,如 ECMAScript 語言規範第 property attributes 一節中定義。
  • 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 呼叫對屬性執行 get 操作)時,執行時會隱式呼叫給定函式。napi_callback 提供了更多詳細資訊。
  • setter: 執行屬性的 set 訪問時呼叫的函式。如果傳入此值,則將 valuemethod 設定為 NULL(因為這些成員不會被使用)。當從 JavaScript 程式碼設定屬性(或使用 Node-API 呼叫對屬性執行 set 操作)時,執行時會隱式呼叫給定函式。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:一個 napi_value,表示一個 JavaScript 值陣列,這些值表示物件的屬性名。napi_get_array_lengthnapi_get_element 可用於迭代 result

如果 API 成功,則返回 napi_ok

此 API 返回一個數組,其中包含此物件的可用屬性的名稱。

napi_set_property#
napi_status napi_set_property(napi_env env,
                              napi_value object,
                              napi_value key,
                              napi_value value); 
  • [in] env: 呼叫 Node-API 的環境。
  • [in] object:要設定屬性的物件。
  • [in] key:要設定的屬性的名稱。
  • [in] value:屬性值。

如果 API 成功,則返回 napi_ok

此 API 在傳入的 Object 上設定一個屬性。

napi_get_property#
napi_status napi_get_property(napi_env env,
                              napi_value object,
                              napi_value key,
                              napi_value* result); 
  • [in] env: 呼叫 Node-API 的環境。
  • [in] object:從中檢索屬性的物件。
  • [in] key:要檢索的屬性的名稱。
  • [out] result:屬性的值。

如果 API 成功,則返回 napi_ok

此 API 從傳入的 Object 中獲取請求的屬性。

napi_has_property#
napi_status napi_has_property(napi_env env,
                              napi_value object,
                              napi_value key,
                              bool* result); 
  • [in] env: 呼叫 Node-API 的環境。
  • [in] object:要查詢的物件。
  • [in] key:要檢查其是否存在屬性的名稱。
  • [out] result:屬性是否存在於物件上。

如果 API 成功,則返回 napi_ok

此 API 檢查傳入的 Object 是否具有指定名稱的屬性。

napi_delete_property#
napi_status napi_delete_property(napi_env env,
                                 napi_value object,
                                 napi_value key,
                                 bool* result); 
  • [in] env: 呼叫 Node-API 的環境。
  • [in] object:要查詢的物件。
  • [in] key:要刪除的屬性的名稱。
  • [out] result:屬性刪除是否成功。可以透過傳入 NULL 來選擇性地忽略 result

如果 API 成功,則返回 napi_ok

此 API 嘗試從 object 中刪除 key 自己的屬性。

napi_has_own_property#
napi_status napi_has_own_property(napi_env env,
                                  napi_value object,
                                  napi_value key,
                                  bool* result); 
  • [in] env: 呼叫 Node-API 的環境。
  • [in] object:要查詢的物件。
  • [in] key:要檢查其是否存在自身屬性的名稱。
  • [out] result:自身屬性是否存在於物件上。

如果 API 成功,則返回 napi_ok

此 API 檢查傳入的 Object 是否具有指定名稱的自身屬性。key 必須是 stringsymbol,否則將丟擲錯誤。Node-API 不會執行任何資料型別之間的轉換。

napi_set_named_property#
napi_status napi_set_named_property(napi_env env,
                                    napi_value object,
                                    const char* utf8Name,
                                    napi_value value); 
  • [in] env: 呼叫 Node-API 的環境。
  • [in] object:要設定屬性的物件。
  • [in] utf8Name:要設定的屬性的名稱。
  • [in] value:屬性值。

如果 API 成功,則返回 napi_ok

此方法等同於呼叫 napi_set_property,其中 napi_value 是由作為 utf8Name 傳入的字串建立的。

napi_get_named_property#
napi_status napi_get_named_property(napi_env env,
                                    napi_value object,
                                    const char* utf8Name,
                                    napi_value* result); 
  • [in] env: 呼叫 Node-API 的環境。
  • [in] object:從中檢索屬性的物件。
  • [in] utf8Name:要獲取的屬性的名稱。
  • [out] result:屬性的值。

如果 API 成功,則返回 napi_ok

此方法等同於呼叫 napi_get_property,其中 napi_value 是由作為 utf8Name 傳入的字串建立的。

napi_has_named_property#
napi_status napi_has_named_property(napi_env env,
                                    napi_value object,
                                    const char* utf8Name,
                                    bool* result); 
  • [in] env: 呼叫 Node-API 的環境。
  • [in] object:要查詢的物件。
  • [in] utf8Name:要檢查其是否存在屬性的名稱。
  • [out] result:屬性是否存在於物件上。

如果 API 成功,則返回 napi_ok

此方法等同於呼叫 napi_has_property,其中 napi_value 是由作為 utf8Name 傳入的字串建立的。

napi_set_element#
napi_status napi_set_element(napi_env env,
                             napi_value object,
                             uint32_t index,
                             napi_value value); 
  • [in] env: 呼叫 Node-API 的環境。
  • [in] object:要設定屬性的物件。
  • [in] index:要設定的屬性的索引。
  • [in] value:屬性值。

如果 API 成功,則返回 napi_ok

此 API 在傳入的 Object 上設定一個元素。

napi_get_element#
napi_status napi_get_element(napi_env env,
                             napi_value object,
                             uint32_t index,
                             napi_value* result); 
  • [in] env: 呼叫 Node-API 的環境。
  • [in] object:從中檢索屬性的物件。
  • [in] index:要獲取的屬性的索引。
  • [out] result:屬性的值。

如果 API 成功,則返回 napi_ok

此 API 獲取請求索引處的元素。

napi_has_element#
napi_status napi_has_element(napi_env env,
                             napi_value object,
                             uint32_t index,
                             bool* result); 
  • [in] env: 呼叫 Node-API 的環境。
  • [in] object:要查詢的物件。
  • [in] index:要檢查其是否存在屬性的索引。
  • [out] result:屬性是否存在於物件上。

如果 API 成功,則返回 napi_ok

此 API 返回傳入的 Object 是否在請求的索引處有一個元素。

napi_delete_element#
napi_status napi_delete_element(napi_env env,
                                napi_value object,
                                uint32_t index,
                                bool* result); 
  • [in] env: 呼叫 Node-API 的環境。
  • [in] object:要查詢的物件。
  • [in] index:要刪除的屬性的索引。
  • [out] result:元素刪除是否成功。可以透過傳入 NULL 來選擇性地忽略 result

如果 API 成功,則返回 napi_ok

此 API 嘗試從 object 中刪除指定的 index

napi_define_properties#
napi_status napi_define_properties(napi_env env,
                                   napi_value object,
                                   size_t property_count,
                                   const napi_property_descriptor* properties); 
  • [in] env: 呼叫 Node-API 的環境。
  • [in] object: 從中檢索屬性的物件。
  • [in] property_countproperties 陣列中的元素數量。
  • [in] properties:屬性描述符陣列。

如果 API 成功,則返回 napi_ok

此方法允許在給定物件上高效定義多個屬性。屬性使用屬性描述符定義(請參閱 napi_property_descriptor)。給定此類屬性描述符陣列,此 API 將根據 DefineOwnProperty()(在 ECMA-262 規範的 DefineOwnProperty 部分 中描述)定義,一次設定物件上的屬性。

napi_object_freeze#
napi_status napi_object_freeze(napi_env env,
                               napi_value object); 
  • [in] env: 呼叫 Node-API 的環境。
  • [in] object:要凍結的物件。

如果 API 成功,則返回 napi_ok

此方法凍結給定物件。這會阻止向其新增新屬性、刪除現有屬性、更改現有屬性的可列舉性、可配置性或可寫性,以及更改現有屬性的值。它還會阻止更改物件的原型。這在 ECMA-262 規範的 第 19.1.2.6 節 中有所描述。

napi_object_seal#
napi_status napi_object_seal(napi_env env,
                             napi_value object); 
  • [in] env: 呼叫 Node-API 的環境。
  • [in] object:要密封的物件。

如果 API 成功,則返回 napi_ok

此方法密封給定物件。這會阻止向其新增新屬性,並將其所有現有屬性標記為不可配置。這在 ECMA-262 規範的 第 19.1.2.20 節 中有所描述。

使用 JavaScript 函式#

Node-API 提供了一組 API,允許 JavaScript 程式碼回撥到原生程式碼中。支援回撥到原生程式碼的 Node-API 接受由 napi_callback 型別表示的回撥函式。當 JavaScript VM 回撥到原生程式碼時,將呼叫提供的 napi_callback 函式。本節中記錄的 API 允許回撥函式執行以下操作:

  • 獲取有關呼叫回撥的上下文的資訊。
  • 獲取傳遞給回撥的引數。
  • 從回撥返回 napi_value

此外,Node-API 提供了一組函式,允許從原生程式碼呼叫 JavaScript 函式。可以像常規 JavaScript 函式呼叫一樣呼叫函式,也可以作為建構函式呼叫。

透過 napi_property_descriptor 項的 data 欄位傳遞給此 API 的任何非 NULL 資料都可以與 object 相關聯,並在 object 被垃圾回收時透過將 object 和資料傳遞給 napi_add_finalizer 來釋放。

napi_call_function#

NAPI_EXTERN napi_status napi_call_function(napi_env env,
                                           napi_value recv,
                                           napi_value func,
                                           size_t argc,
                                           const napi_value* argv,
                                           napi_value* result); 
  • [in] env: 呼叫 API 的環境。
  • [in] recv:傳遞給被呼叫函式的 this 值。
  • [in] func:表示要呼叫的 JavaScript 函式的 napi_value
  • [in] argcargv 陣列中的元素數量。
  • [in] argvnapi_value 陣列,表示作為引數傳遞給函式的 JavaScript 值。
  • [out] result:表示返回的 JavaScript 物件的 napi_value

如果 API 成功,則返回 napi_ok

此方法允許從原生外掛呼叫 JavaScript 函式物件。這是從外掛的原生程式碼*到* JavaScript 回撥的主要機制。對於非同步操作後呼叫 JavaScript 的特殊情況,請參閱 napi_make_callback

一個示例用例可能如下所示。考慮以下 JavaScript 片段

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

然後,可以使用以下程式碼從原生外掛呼叫上述函式

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

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

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

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

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

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

napi_create_function#

napi_status napi_create_function(napi_env env,
                                 const char* utf8name,
                                 size_t length,
                                 napi_callback cb,
                                 void* data,
                                 napi_value* result); 
  • [in] env: 呼叫 API 的環境。
  • [in] utf8Name:函式的可選名稱,編碼為 UTF8。這在 JavaScript 中作為新函式物件的 name 屬性可見。
  • [in] lengthutf8name 的位元組長度,如果以 null 結尾,則為 NAPI_AUTO_LENGTH
  • [in] cb:當此函式物件被呼叫時應該呼叫的原生函式。napi_callback 提供更多詳細資訊。
  • [in] data:使用者提供的資料上下文。稍後呼叫時將傳遞迴函式。
  • [out] result:表示新建立函式的 JavaScript 函式物件的 napi_value

如果 API 成功,則返回 napi_ok

此 API 允許外掛作者在原生程式碼中建立函式物件。這是允許從 JavaScript *呼叫*到外掛原生程式碼的主要機制。

此呼叫後,新建立的函式不會自動從指令碼中可見。相反,必須在任何對 JavaScript 可見的物件上顯式設定一個屬性,以便指令碼可以訪問該函式。

為了將函式作為外掛模組匯出的一部分公開,請在新建立的函式上設定匯出物件。一個示例模組可能如下所示

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 語言規範的 函式物件部分 中描述。

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] cons:表示要作為建構函式呼叫的 JavaScript 函式的 napi_value
  • [in] argcargv 陣列中的元素數量。
  • [in] argv:作為 napi_value 的 JavaScript 值陣列,表示傳遞給建構函式的引數。如果 argc 為零,則此引數可以透過傳入 NULL 來省略。
  • [out] result:表示返回的 JavaScript 物件的 napi_value,在這種情況下是構造的物件。

此方法用於使用表示物件建構函式的給定 napi_value 例項化新的 JavaScript 值。例如,考慮以下片段

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

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

以下內容可以使用以下片段在 Node-API 中近似實現

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

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

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

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

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

如果 API 成功,則返回 napi_ok

物件包裝#

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 物件是某個原生型別的包裝器。尤其是在透過靜態方法而不是作為原型方法的 this 值將包裝的 JavaScript 物件傳遞迴外掛時,更是如此。在這種情況下,它們可能會被錯誤地解包。

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() 的實現必須執行型別驗證。保留例項化資料庫控制代碼的 JavaScript 類建構函式和例項化查詢控制代碼的建構函式在 napi_ref 中可以提供幫助,因為 napi_instanceof() 可以用於確保傳遞給 queryHashRecords() 的例項確實是正確的型別。

不幸的是,napi_instanceof() 不能防止原型操作。例如,資料庫控制代碼例項的原型可以設定為查詢控制代碼例項的建構函式的原型。在這種情況下,資料庫控制代碼例項可以顯示為查詢控制代碼例項,並且它將透過查詢控制代碼例項的 napi_instanceof() 測試,同時仍然包含指向資料庫控制代碼的指標。

為此,Node-API 提供了型別標記功能。

型別標籤是外掛獨有的 128 位整數。Node-API 提供了 napi_type_tag 結構來儲存型別標籤。當將此類值與儲存在 napi_value 中的 JavaScript 物件或 外部物件 一起傳遞給 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++ 類的*非靜態*資料屬性、訪問器和方法可以在檢索到使用 napi_unwrap 放置在 JavaScript 物件例項中的 C++ 類例項後,從不帶 napi_static 屬性的屬性描述符中給出的靜態函式中呼叫。

在包裝 C++ 類時,透過 constructor 傳遞的 C++ 建構函式回撥應該是類上的靜態方法,該方法呼叫實際的類建構函式,然後將新的 C++ 例項包裝在 JavaScript 物件中,並返回包裝器物件。有關詳細資訊,請參閱 napi_wrap

napi_define_class 返回的 JavaScript 建構函式通常會儲存下來,稍後用於從原生程式碼構造類的新例項,和/或檢查提供的值是否是該類的例項。在這種情況下,為了防止函式值被垃圾回收,可以使用 napi_create_reference 建立對其的強持久引用,確保引用計數保持 >= 1。

透過 data 引數或透過 napi_property_descriptor 陣列項的 data 欄位傳遞給此 API 的任何非 NULL 資料都可以與生成的 JavaScript 建構函式(在 result 引數中返回)相關聯,並在類被垃圾回收時透過將 JavaScript 函式和資料傳遞給 napi_add_finalizer 來釋放。

napi_wrap#

napi_status napi_wrap(napi_env env,
                      napi_value js_object,
                      void* native_object,
                      napi_finalize finalize_cb,
                      void* finalize_hint,
                      napi_ref* result); 
  • [in] env: 呼叫 API 的環境。
  • [in] js_object:將作為原生物件包裝器的 JavaScript 物件。
  • [in] native_object:將包裝在 JavaScript 物件中的原生例項。
  • [in] finalize_cb:可選的原生回撥,當 JavaScript 物件被垃圾回收時可用於釋放原生例項。napi_finalize 提供了更多詳細資訊。
  • [in] finalize_hint:傳遞給終結器回撥的可選上下文提示。
  • [out] result:對包裝物件的可選引用。

如果 API 成功,則返回 napi_ok

將原生例項包裝在 JavaScript 物件中。原生例項稍後可以使用 napi_unwrap() 檢索。

當 JavaScript 程式碼呼叫使用 napi_define_class() 定義的類的建構函式時,將呼叫建構函式的 napi_callback。在構造原生類的例項之後,回撥必須呼叫 napi_wrap() 將新構造的例項包裝在已建立的 JavaScript 物件中,該物件是建構函式回撥的 this 引數。(該 this 物件是從建構函式的 prototype 建立的,因此它已經具有所有例項屬性和方法的定義。)

通常在包裝類例項時,應該提供一個終結器回撥,該回調簡單地刪除作為終結器回撥的 data 引數接收的原生例項。

可選的返回引用最初是一個弱引用,這意味著它的引用計數為 0。通常,在需要例項保持有效的非同步操作期間,此引用計數會暫時增加。

注意:可選的返回引用(如果已獲取)應僅響應終結器回撥呼叫透過 napi_delete_reference 刪除。如果在此之前刪除,則終結器回撥可能永遠不會被呼叫。因此,在獲取引用時,還需要一個終結器回撥,以實現引用的正確處置。

終結器回撥可能會被延遲,留下一個物件已被垃圾回收(並且弱引用無效)但終結器尚未被呼叫的時間視窗。當在 napi_wrap() 返回的弱引用上使用 napi_get_reference_value() 時,仍應處理空結果。

在物件上第二次呼叫 napi_wrap() 將返回錯誤。要將另一個原生例項與物件關聯,請首先使用 napi_remove_wrap()

napi_unwrap#

napi_status napi_unwrap(napi_env env,
                        napi_value js_object,
                        void** result); 
  • [in] env: 呼叫 API 的環境。
  • [in] js_object:與原生例項關聯的物件。
  • [out] result:指向包裝的原生例項的指標。

如果 API 成功,則返回 napi_ok

檢索先前使用 napi_wrap() 包裝在 JavaScript 物件中的原生例項。

當 JavaScript 程式碼呼叫類上的方法或屬性訪問器時,將呼叫相應的 napi_callback。如果回撥用於例項方法或訪問器,則回撥的 this 引數是包裝器物件;然後可以透過在包裝器物件上呼叫 napi_unwrap() 來獲取作為呼叫目標的包裝 C++ 例項。

napi_remove_wrap#

napi_status napi_remove_wrap(napi_env env,
                             napi_value js_object,
                             void** result); 
  • [in] env: 呼叫 API 的環境。
  • [in] js_object:與原生例項關聯的物件。
  • [out] result:指向包裝的原生例項的指標。

如果 API 成功,則返回 napi_ok

檢索先前使用 napi_wrap() 包裝在 JavaScript 物件 js_object 中的原生例項並移除包裝。如果終結器回撥與包裝關聯,則當 JavaScript 物件被垃圾回收時將不再呼叫它。

napi_type_tag_object#

napi_status napi_type_tag_object(napi_env env,
                                 napi_value js_object,
                                 const napi_type_tag* type_tag); 
  • [in] env: 呼叫 API 的環境。
  • [in] js_object:要標記的 JavaScript 物件或 外部物件
  • [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,
                               node_api_basic_finalize finalize_cb,
                               void* finalize_hint,
                               napi_ref* result); 
  • [in] env: 呼叫 API 的環境。
  • [in] js_object:要附加原生資料的 JavaScript 物件。
  • [in] finalize_data:可選資料,將傳遞給 finalize_cb
  • [in] finalize_cb:原生回撥,當 JavaScript 物件被垃圾回收時將用於釋放原生資料。napi_finalize 提供了更多詳細資訊。
  • [in] finalize_hint:傳遞給終結器回撥的可選上下文提示。
  • [out] result:對 JavaScript 物件的可選引用。

如果 API 成功,則返回 napi_ok

新增一個 napi_finalize 回撥,當 js_object 中的 JavaScript 物件被垃圾回收時將呼叫它。

此 API 可以在單個 JavaScript 物件上多次呼叫。

注意:可選的返回引用(如果已獲取)應僅響應終結器回撥呼叫透過 napi_delete_reference 刪除。如果在此之前刪除,則終結器回撥可能永遠不會被呼叫。因此,在獲取引用時,還需要一個終結器回撥,以實現引用的正確處置。

node_api_post_finalizer#

穩定性:1 - 實驗性

napi_status node_api_post_finalizer(node_api_basic_env env,
                                    napi_finalize finalize_cb,
                                    void* finalize_data,
                                    void* finalize_hint); 
  • [in] env: 呼叫 API 的環境。
  • [in] finalize_cb:原生回撥,當 JavaScript 物件被垃圾回收時將用於釋放原生資料。napi_finalize 提供了更多詳細資訊。
  • [in] finalize_data:可選資料,將傳遞給 finalize_cb
  • [in] finalize_hint:傳遞給終結器回撥的可選上下文提示。

如果 API 成功,則返回 napi_ok

安排在事件迴圈中非同步呼叫 napi_finalize 回撥。

通常,終結器在 GC(垃圾回收器)收集物件時被呼叫。此時,任何可能導致 GC 狀態更改的 Node-API 呼叫都將被停用,並將導致 Node.js 崩潰。

node_api_post_finalizer 透過允許外掛將此類 Node-API 的呼叫推遲到 GC 終結之外的時間點,從而幫助解決此限制。

簡單的非同步操作#

外掛模組通常需要利用 libuv 的非同步助手作為其實現的一部分。這允許它們安排工作以非同步執行,以便它們的方法可以在工作完成之前返回。這使它們可以避免阻塞 Node.js 應用程式的整體執行。

Node-API 為這些支援函式提供了一個 ABI 穩定的介面,涵蓋了最常見的非同步用例。

Node-API 定義了 napi_async_work 結構,用於管理非同步工作器。例項使用 napi_create_async_worknapi_delete_async_work 建立/刪除。

executecomplete 回撥是分別在執行器準備好執行和完成任務時呼叫的函式。

execute 函式應避免進行任何可能導致 JavaScript 執行或與 JavaScript 物件互動的 Node-API 呼叫。通常,任何需要進行 Node-API 呼叫的程式碼都應在 complete 回撥中進行。避免在 execute 回撥中使用 napi_env 引數,因為它可能會執行 JavaScript。

這些函式實現以下介面

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

當這些方法被呼叫時,傳遞的 data 引數將是傳入 napi_create_async_work 呼叫的外掛提供的 void* 資料。

建立後,非同步工作器可以使用 napi_queue_async_work 函式排隊等待執行

napi_status napi_queue_async_work(node_api_basic_env env,
                                  napi_async_work work); 

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

呼叫 napi_cancel_async_work 後,將呼叫 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:使用者提供的資料上下文。這將傳遞迴 execute 和 complete 函式。
  • [out] resultnapi_async_work*,它是新建立的非同步工作的控制代碼。

如果 API 成功,則返回 napi_ok

此 API 分配一個工作物件,用於非同步執行邏輯。一旦不再需要,應使用 napi_delete_async_work 釋放它。

async_resource_name 應該是一個以 null 結尾的 UTF-8 編碼字串。

async_resource_name 識別符號由使用者提供,應代表正在執行的非同步工作的型別。建議對識別符號應用名稱空間,例如,透過包含模組名稱。有關更多資訊,請參閱 async_hooks 文件

napi_delete_async_work#

napi_status napi_delete_async_work(napi_env env,
                                   napi_async_work work); 
  • [in] env: 呼叫 API 的環境。
  • [in] work:呼叫 napi_create_async_work 返回的控制代碼。

如果 API 成功,則返回 napi_ok

此 API 釋放先前分配的工作物件。

即使有待處理的 JavaScript 異常,也可以呼叫此 API。

napi_queue_async_work#

napi_status napi_queue_async_work(node_api_basic_env env,
                                  napi_async_work work); 
  • [in] env: 呼叫 API 的環境。
  • [in] work:呼叫 napi_create_async_work 返回的控制代碼。

如果 API 成功,則返回 napi_ok

此 API 請求將先前分配的工作安排執行。一旦成功返回,此 API 不得再次使用相同的 napi_async_work 項呼叫,否則結果將未定義。

napi_cancel_async_work#

napi_status napi_cancel_async_work(node_api_basic_env env,
                                   napi_async_work work); 
  • [in] env: 呼叫 API 的環境。
  • [in] work:呼叫 napi_create_async_work 返回的控制代碼。

如果 API 成功,則返回 napi_ok

如果排隊的工作尚未開始,此 API 將取消它。如果它已經開始執行,則無法取消,並將返回 napi_generic_failure。如果成功,將呼叫 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

為了保持與以前版本的 ABI 相容性,為 async_resource 傳遞 NULL 不會導致錯誤。但是,不建議這樣做,因為這會導致 async_hooks init 鉤子async_hooks.executionAsyncResource() 出現不良行為,因為底層 async_hooks 實現現在需要該資源才能提供非同步回撥之間的連結。

此 API 的早期版本在 napi_async_context 物件存在時沒有保持對 async_resource 的強引用,而是期望呼叫者保持強引用。這已更改,因為在任何情況下,每次呼叫 napi_async_init() 都必須相應地呼叫 napi_async_destroy 以避免記憶體洩漏。

napi_async_destroy#

napi_status napi_async_destroy(napi_env env,
                               napi_async_context async_context); 
  • [in] env: 呼叫 API 的環境。
  • [in] async_context:要銷燬的非同步上下文。

如果 API 成功,則返回 napi_ok

即使有待處理的 JavaScript 異常,也可以呼叫此 API。

napi_make_callback#

NAPI_EXTERN napi_status napi_make_callback(napi_env env,
                                           napi_async_context async_context,
                                           napi_value recv,
                                           napi_value func,
                                           size_t argc,
                                           const napi_value* argv,
                                           napi_value* result); 
  • [in] env: 呼叫 API 的環境。
  • [in] async_context:呼叫回撥的非同步操作的上下文。這通常應該是先前從 napi_async_init 獲取的值。為了保持與以前版本的 ABI 相容性,為 async_context 傳遞 NULL 不會導致錯誤。但是,這會導致非同步鉤子的操作不正確。潛在問題包括使用 AsyncLocalStorage API 時非同步上下文的丟失。
  • [in] recv:傳遞給被呼叫函式的 this 值。
  • [in] func:表示要呼叫的 JavaScript 函式的 napi_value
  • [in] argcargv 陣列中的元素數量。
  • [in] argv:作為 napi_value 的 JavaScript 值陣列,表示函式的引數。如果 argc 為零,則此引數可以透過傳入 NULL 來省略。
  • [out] result:表示返回的 JavaScript 物件的 napi_value

如果 API 成功,則返回 napi_ok

此方法允許從原生外掛呼叫 JavaScript 函式物件。此 API 類似於 napi_call_function。但是,它用於在非同步操作返回後(當堆疊上沒有其他指令碼時)從原生程式碼回撥到 JavaScript。它是 node::MakeCallback 的一個相當簡單的包裝器。

請注意,從 napi_async_complete_callback 中使用 napi_make_callback *不是*必需的;在這種情況下,回撥的非同步上下文已設定好,因此直接呼叫 napi_call_function 足夠且合適。當實現不使用 napi_create_async_work 的自定義非同步行為時,可能需要使用 napi_make_callback 函式。

JavaScript 在回撥期間安排在微任務佇列上的任何 process.nextTick 或 Promises 都會在返回 C/C++ 之前執行。

napi_open_callback_scope#

NAPI_EXTERN napi_status napi_open_callback_scope(napi_env env,
                                                 napi_value resource_object,
                                                 napi_async_context context,
                                                 napi_callback_scope* result) 
  • [in] env: 呼叫 API 的環境。
  • [in] resource_object:與非同步工作關聯的物件,將傳遞給可能的 async_hooks init 鉤子。此引數已棄用,在執行時被忽略。請改用 napi_async_init 中的 async_resource 引數。
  • [in] context:呼叫回撥的非同步操作的上下文。這應該是先前從 napi_async_init 獲取的值。
  • [out] result:新建立的作用域。

在某些情況下(例如,解決 Promises),在進行某些 Node-API 呼叫時,需要存在與回撥關聯的等效作用域。如果堆疊上沒有其他指令碼,則可以使用 napi_open_callback_scopenapi_close_callback_scope 函式開啟/關閉所需的作用域。

napi_close_callback_scope#

NAPI_EXTERN napi_status napi_close_callback_scope(napi_env env,
                                                  napi_callback_scope scope) 
  • [in] env: 呼叫 API 的環境。
  • [in] scope:要關閉的作用域。

即使有待處理的 JavaScript 異常,也可以呼叫此 API。

版本管理#

napi_get_node_version#

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

napi_status napi_get_node_version(node_api_basic_env env,
                                  const napi_node_version** version); 
  • [in] env: 呼叫 API 的環境。
  • [out] version:指向 Node.js 自身版本資訊的指標。

如果 API 成功,則返回 napi_ok

此函式用當前執行的 Node.js 的主版本、次版本和補丁版本填充 version 結構,並用 process.release.name 的值填充 release 欄位。

返回的緩衝區是靜態分配的,不需要釋放。

napi_get_version#

napi_status napi_get_version(node_api_basic_env env,
                             uint32_t* result); 
  • [in] env: 呼叫 API 的環境。
  • [out] result:支援的最高 Node-API 版本。

如果 API 成功,則返回 napi_ok

此 API 返回 Node.js 執行時支援的最高 Node-API 版本。Node-API 計劃是增量的,以便 Node.js 的新版本可能支援額外的 API 函式。為了允許外掛在執行支援它的 Node.js 版本時使用較新的函式,同時在執行不支援它的 Node.js 版本時提供回退行為

  • 呼叫 napi_get_version() 以確定 API 是否可用。
  • 如果可用,使用 uv_dlsym() 動態載入函式指標。
  • 使用動態載入的指標呼叫函式。
  • 如果函式不可用,則提供不使用該函式的替代實現。

記憶體管理#

napi_adjust_external_memory#

NAPI_EXTERN napi_status napi_adjust_external_memory(node_api_basic_env env,
                                                    int64_t change_in_bytes,
                                                    int64_t* result); 
  • [in] env: 呼叫 API 的環境。
  • [in] change_in_bytes:由 JavaScript 物件保持活躍的外部分配記憶體的變化量。
  • [out] result:調整後的值。此值應反映包含給定 change_in_bytes 的外部記憶體總量。不應依賴返回值的絕對值。例如,實現可能為所有外掛使用單個計數器,或者為每個外掛使用一個計數器。

如果 API 成功,則返回 napi_ok

此函式向執行時指示由 JavaScript 物件保持活躍的外部分配記憶體量(即指向其自己的由原生外掛分配的記憶體的 JavaScript 物件)。註冊外部分配的記憶體可能會(但不能保證)比否則更頻繁地觸發全域性垃圾回收。

此函式應以外掛不會減少外部記憶體超過其增加外部記憶體的方式呼叫。

Promises#

Node-API 提供了建立 Promise 物件的功能,如 ECMA 規範的 Promise 物件部分 中所述。它將 Promises 實現為一對物件。當透過 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() 將執行其非同步操作,然後它將解決或拒絕延遲,從而結束 Promise 並釋放延遲

napi_deferred deferred;
napi_value undefined;
napi_status status;

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

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

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

napi_create_promise#

napi_status napi_create_promise(napi_env env,
                                napi_deferred* deferred,
                                napi_value* promise); 
  • [in] env: 呼叫 API 的環境。
  • [out] deferred:一個新建立的延遲物件,稍後可以傳遞給 napi_resolve_deferred()napi_reject_deferred() 以分別解決或拒絕關聯的 Promise。
  • [out] promise:與延遲物件關聯的 JavaScript promise。

如果 API 成功,則返回 napi_ok

此 API 建立一個延遲物件和一個 JavaScript Promise。

napi_resolve_deferred#

napi_status napi_resolve_deferred(napi_env env,
                                  napi_deferred deferred,
                                  napi_value resolution); 
  • [in] env: 呼叫 API 的環境。
  • [in] deferred:其關聯的 Promise 要解決的延遲物件。
  • [in] resolution:用於解決 Promise 的值。

此 API 透過其關聯的延遲物件解決 JavaScript promise。因此,它只能用於解決相應延遲物件可用的 JavaScript promise。這實際上意味著 promise 必須已使用 napi_create_promise() 建立,並且從該呼叫返回的延遲物件必須已保留,以便傳遞給此 API。

延遲物件在成功完成後被釋放。

napi_reject_deferred#

napi_status napi_reject_deferred(napi_env env,
                                 napi_deferred deferred,
                                 napi_value rejection); 
  • [in] env: 呼叫 API 的環境。
  • [in] deferred:其關聯的 Promise 要解決的延遲物件。
  • [in] rejection:用於拒絕 Promise 的值。

此 API 透過其關聯的延遲物件拒絕 JavaScript promise。因此,它只能用於拒絕相應延遲物件可用的 JavaScript promise。這實際上意味著 promise 必須已使用 napi_create_promise() 建立,並且從該呼叫返回的延遲物件必須已保留,以便傳遞給此 API。

延遲物件在成功完成後被釋放。

napi_is_promise#

napi_status napi_is_promise(napi_env env,
                            napi_value value,
                            bool* is_promise); 
  • [in] env: 呼叫 API 的環境。
  • [in] value:要檢查的值
  • [out] is_promise:指示 promise 是否為原生 promise 物件的標誌(即,由底層引擎建立的 promise 物件)。

指令碼執行#

Node-API 提供了一個 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(node_api_basic_env env,
                                               struct uv_loop_s** loop); 
  • [in] env: 呼叫 API 的環境。
  • [out] loop:當前的 libuv 迴圈例項。

注意:雖然 libuv 隨著時間的推移相對穩定,但它不提供 ABI 穩定性保證。應避免使用此函式。它的使用可能導致外掛在不同 Node.js 版本之間無法工作。asynchronous-thread-safe-function-calls 是許多用例的替代方案。

非同步執行緒安全函式呼叫#

JavaScript 函式通常只能從原生外掛的主執行緒呼叫。如果外掛建立了額外的執行緒,則需要 napi_envnapi_valuenapi_ref 的 Node-API 函式不得從這些執行緒呼叫。

當外掛有額外的執行緒,並且需要根據這些執行緒完成的處理呼叫 JavaScript 函式時,這些執行緒必須與外掛的主執行緒通訊,以便主執行緒可以代表它們呼叫 JavaScript 函式。執行緒安全函式 API 提供了一種簡單的方法來實現這一點。

這些 API 提供了 napi_threadsafe_function 型別以及建立、銷燬和呼叫此型別物件的 API。napi_create_threadsafe_function() 建立對 napi_value 的持久引用,該 napi_value 持有可以從多個執行緒呼叫的 JavaScript 函式。呼叫是非同步發生的。這意味著要呼叫 JavaScript 回撥的值將放入佇列中,並且對於佇列中的每個值,最終將對 JavaScript 函式進行呼叫。

建立 napi_threadsafe_function 後,可以提供一個 napi_finalize 回撥。當執行緒安全函式即將被銷燬時,將在主執行緒上呼叫此回撥。它接收在構造過程中給出的上下文和終結資料,並提供一個清理執行緒的機會,例如透過呼叫 uv_thread_join()除了主迴圈執行緒之外,在終結器回撥完成後,任何執行緒都不應使用執行緒安全函式。

在呼叫 napi_create_threadsafe_function() 期間給定的 context 可以透過呼叫 napi_get_threadsafe_function_context() 從任何執行緒檢索。

呼叫執行緒安全函式#

napi_call_threadsafe_function() 可用於發起對 JavaScript 的呼叫。napi_call_threadsafe_function() 接受一個引數,該引數控制 API 的阻塞行為。如果設定為 napi_tsfn_nonblocking,則 API 表現為非阻塞,如果佇列已滿,則返回 napi_queue_full,從而阻止資料成功新增到佇列中。如果設定為 napi_tsfn_blocking,則 API 將阻塞,直到佇列中出現可用空間。如果執行緒安全函式是以最大佇列大小為 0 建立的,則 napi_call_threadsafe_function() 永遠不會阻塞。

不應從 JavaScript 執行緒呼叫 napi_call_threadsafe_function() 並使用 napi_tsfn_blocking,因為如果佇列已滿,它可能導致 JavaScript 執行緒死鎖。

實際的 JavaScript 呼叫由透過 call_js_cb 引數給出的回撥控制。call_js_cb 在主執行緒上被呼叫,每次成功呼叫 napi_call_threadsafe_function() 將一個值放入佇列時。如果未給出此類回撥,將使用預設回撥,並且生成的 JavaScript 呼叫將沒有引數。call_js_cb 回撥在其引數中接收要呼叫的 JavaScript 函式作為 napi_value,以及建立 napi_threadsafe_function 時使用的 void* 上下文指標,以及由其中一個輔助執行緒建立的下一個資料指標。然後回撥可以使用 napi_call_function() 等 API 呼叫 JavaScript。

回撥也可能在 envcall_js_cb 都設定為 NULL 的情況下被呼叫,以指示無法再進行 JavaScript 呼叫,而佇列中仍有需要釋放的專案。這通常發生在 Node.js 程序退出時,而執行緒安全函式仍然處於活動狀態。

沒有必要透過 napi_make_callback() 呼叫 JavaScript,因為 Node-API 在適合回撥的上下文中執行 call_js_cb

在事件迴圈的每個 tick 中,可以呼叫零個或更多個排隊項。應用程式不應依賴於特定的行為,除了呼叫回撥的進度將得到實現,並且事件將隨著時間的推移而呼叫。

執行緒安全函式的引用計數#

napi_threadsafe_function 物件的生命週期內,執行緒可以被新增和移除。因此,除了在建立時指定初始執行緒數之外,還可以呼叫 napi_acquire_threadsafe_function 來指示新執行緒將開始使用執行緒安全函式。同樣,可以呼叫 napi_release_threadsafe_function 來指示現有執行緒將停止使用執行緒安全函式。

當使用該物件的每個執行緒都已呼叫 napi_release_threadsafe_function() 或在呼叫 napi_call_threadsafe_function 時收到 napi_closing 返回狀態時,napi_threadsafe_function 物件將被銷燬。在 napi_threadsafe_function 銷燬之前,佇列將被清空。napi_release_threadsafe_function() 應該是與給定 napi_threadsafe_function 相關的最後一個 API 呼叫,因為在該呼叫完成後,無法保證 napi_threadsafe_function 仍然被分配。出於同樣的原因,在收到 napi_call_threadsafe_function 呼叫返回 napi_closing 值後,不要再使用執行緒安全函式。與 napi_threadsafe_function 關聯的資料可以在其傳遞給 napi_create_threadsafe_function()napi_finalize 回撥中釋放。napi_create_threadsafe_function 的引數 initial_thread_count 標記了執行緒安全函式的初始獲取次數,而不是在建立時多次呼叫 napi_acquire_threadsafe_function

一旦使用 napi_threadsafe_function 的執行緒數達到零,就沒有其他執行緒可以透過呼叫 napi_acquire_threadsafe_function() 開始使用它。事實上,所有與其相關的後續 API 呼叫,除了 napi_release_threadsafe_function(),都將返回 napi_closing 錯誤值。

執行緒安全函式可以透過向 napi_release_threadsafe_function() 傳遞 napi_tsfn_abort 值來“中止”。這將導致與執行緒安全函式關聯的所有後續 API(除了 napi_release_threadsafe_function())返回 napi_closing,即使其引用計數尚未達到零。特別是,napi_call_threadsafe_function() 將返回 napi_closing,從而通知執行緒無法再對執行緒安全函式進行非同步呼叫。這可以用作終止執行緒的標準。napi_call_threadsafe_function() 接收到 napi_closing 返回值後,執行緒不得再使用執行緒安全函式,因為不再保證它已分配。

決定是否保持程序執行#

與 libuv 控制代碼類似,執行緒安全函式可以被“引用”和“取消引用”。“引用”的執行緒安全函式將導致在其上建立的執行緒上的事件迴圈保持活躍,直到執行緒安全函式被銷燬。相反,“未引用”的執行緒安全函式不會阻止事件迴圈退出。為此目的存在 API napi_ref_threadsafe_functionnapi_unref_threadsafe_function

napi_unref_threadsafe_function 既不將執行緒安全函式標記為可銷燬,napi_ref_threadsafe_function 也不阻止其銷燬。

napi_create_threadsafe_function#

NAPI_EXTERN napi_status
napi_create_threadsafe_function(napi_env env,
                                napi_value func,
                                napi_value async_resource,
                                napi_value async_resource_name,
                                size_t max_queue_size,
                                size_t initial_thread_count,
                                void* thread_finalize_data,
                                napi_finalize thread_finalize_cb,
                                void* context,
                                napi_threadsafe_function_call_js call_js_cb,
                                napi_threadsafe_function* result); 
  • [in] env: 呼叫 API 的環境。
  • [in] func:一個可選的 JavaScript 函式,用於從另一個執行緒呼叫。如果 call_js_cb 傳入 NULL,則必須提供此引數。
  • [in] async_resource:與非同步工作關聯的可選物件,將傳遞給可能的 async_hooks init 鉤子
  • [in] async_resource_name:一個 JavaScript 字串,提供一種資源的識別符號,用於 async_hooks API 公開的診斷資訊。
  • [in] max_queue_size:佇列的最大大小。0 表示無限制。
  • [in] initial_thread_count:初始獲取次數,即包括主執行緒在內,將使用此函式的初始執行緒數。
  • [in] thread_finalize_data:可選資料,將傳遞給 thread_finalize_cb
  • [in] thread_finalize_cb:當 napi_threadsafe_function 被銷燬時呼叫的可選函式。
  • [in] context:要附加到結果 napi_threadsafe_function 的可選資料。
  • [in] call_js_cb:可選回撥,用於響應不同執行緒上的呼叫來呼叫 JavaScript 函式。此回撥將在主執行緒上呼叫。如果未給出,JavaScript 函式將不帶引數且其 this 值為 undefined 被呼叫。napi_threadsafe_function_call_js 提供了更多詳細資訊。
  • [out] result:非同步執行緒安全 JavaScript 函式。

變更歷史

  • 版本 10 (已定義 NAPI_VERSION10 或更高)

    call_js_cb 中丟擲的未捕獲異常將使用 'uncaughtException' 事件處理,而不是被忽略。

napi_get_threadsafe_function_context#

NAPI_EXTERN napi_status
napi_get_threadsafe_function_context(napi_threadsafe_function func,
                                     void** result); 
  • [in] func:要檢索上下文的執行緒安全函式。
  • [out] result:儲存上下文的位置。

此 API 可以從使用 func 的任何執行緒呼叫。

napi_call_threadsafe_function#

NAPI_EXTERN napi_status
napi_call_threadsafe_function(napi_threadsafe_function func,
                              void* data,
                              napi_threadsafe_function_call_mode is_blocking); 
  • [in] func:要呼叫的非同步執行緒安全 JavaScript 函式。
  • [in] data:透過在建立執行緒安全 JavaScript 函式期間提供的回撥 call_js_cb 傳送到 JavaScript 的資料。
  • [in] is_blocking:標誌,其值可以是 napi_tsfn_blocking,表示如果佇列已滿則呼叫應阻塞,或者 napi_tsfn_nonblocking,表示如果佇列已滿則呼叫應立即返回 napi_queue_full 狀態。

不應從 JavaScript 執行緒呼叫 napi_call_threadsafe_function() 並使用 napi_tsfn_blocking,因為如果佇列已滿,它可能導致 JavaScript 執行緒死鎖。

如果從任何執行緒呼叫 napi_release_threadsafe_function() 並將 abort 設定為 napi_tsfn_abort,此 API 將返回 napi_closing。只有當 API 返回 napi_ok 時,值才會被新增到佇列中。

此 API 可以從使用 func 的任何執行緒呼叫。

napi_acquire_threadsafe_function#

NAPI_EXTERN napi_status
napi_acquire_threadsafe_function(napi_threadsafe_function func); 
  • [in] func:要開始使用的非同步執行緒安全 JavaScript 函式。

一個執行緒應在將 func 傳遞給任何其他執行緒安全函式 API 之前呼叫此 API,以指示它將使用 func。這可以防止 func 在所有其他執行緒停止使用它時被銷燬。

此 API 可以從將開始使用 func 的任何執行緒呼叫。

napi_release_threadsafe_function#

NAPI_EXTERN napi_status
napi_release_threadsafe_function(napi_threadsafe_function func,
                                 napi_threadsafe_function_release_mode mode); 
  • [in] func:要遞減引用計數的非同步執行緒安全 JavaScript 函式。
  • [in] mode:標誌,其值可以是 napi_tsfn_release,表示當前執行緒將不再對執行緒安全函式進行任何呼叫,或者 napi_tsfn_abort,表示除了當前執行緒之外,任何其他執行緒也不應再對執行緒安全函式進行任何呼叫。如果設定為 napi_tsfn_abort,則對 napi_call_threadsafe_function() 的後續呼叫將返回 napi_closing,並且不再有值放入佇列中。

一個執行緒應該在停止使用 func 時呼叫此 API。在呼叫此 API 後將 func 傳遞給任何執行緒安全 API 會導致未定義的結果,因為 func 可能已被銷燬。

此 API 可以從將停止使用 func 的任何執行緒呼叫。

napi_ref_threadsafe_function#

NAPI_EXTERN napi_status
napi_ref_threadsafe_function(node_api_basic_env env, napi_threadsafe_function func); 
  • [in] env: 呼叫 API 的環境。
  • [in] func:要引用的執行緒安全函式。

此 API 用於指示在主執行緒上執行的事件迴圈不應退出,直到 func 被銷燬。類似於 uv_ref,它也是冪等的。

napi_unref_threadsafe_function 既不將執行緒安全函式標記為可銷燬,napi_ref_threadsafe_function 也不阻止其銷燬。napi_acquire_threadsafe_functionnapi_release_threadsafe_function 用於此目的。

此 API 只能從主執行緒呼叫。

napi_unref_threadsafe_function#

NAPI_EXTERN napi_status
napi_unref_threadsafe_function(node_api_basic_env env, napi_threadsafe_function func); 
  • [in] env: 呼叫 API 的環境。
  • [in] func:要取消引用的執行緒安全函式。

此 API 用於指示在主執行緒上執行的事件迴圈可以在 func 銷燬之前退出。類似於 uv_unref,它也是冪等的。

此 API 只能從主執行緒呼叫。

雜項實用程式#

node_api_get_module_file_name#

NAPI_EXTERN napi_status
node_api_get_module_file_name(node_api_basic_env env, const char** result);
 
  • [in] env: 呼叫 API 的環境。
  • [out] result:一個 URL,包含載入外掛的絕對路徑。對於本地檔案系統上的檔案,它將以 file:// 開頭。該字串以 null 結尾,由 env 擁有,因此不得修改或釋放。

如果外掛載入過程在載入期間未能確定外掛的檔名,則 result 可能為空字串。