Node-API#

穩定度:2 - 穩定

Node-API (原稱 N-API) 是一種用於建置原生附加元件的 API。它獨立於底層 JavaScript 執行時期(例如 V8),並作為 Node.js 本身的一部分進行維護。此 API 將在 Node.js 的各個版本之間保持應用程式二進位介面 (ABI) 的穩定。其目的是將附加元件與底層 JavaScript 引擎的變更隔離開來,並允許針對某個主要版本編譯的模組在後續的 Node.js 主要版本上執行,而無需重新編譯。ABI 穩定性指南提供了更深入的說明。

附加元件的建置/打包方式與標題為 C++ 附加元件章節中所述的方法相同。唯一的區別在於原生程式碼所使用的 API 集合。開發者不再使用 V8 或 Native Abstractions for Node.js API,而是使用 Node-API 中提供的函數。

Node-API 所暴露的 API 通常用於建立和操作 JavaScript 值。其概念與運算大致對應於 ECMA-262 語言規範中指定的概念。這些 API 具有以下屬性:

  • 所有 Node-API 呼叫都會回傳一個 napi_status 型別的狀態碼。此狀態指示 API 呼叫是成功還是失敗。
  • API 的回傳值是透過輸出參數 (out parameter) 傳遞的。
  • 所有 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-apiAPI 文件開始。

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 值。位元旗標列舉型別應有明確的文件說明,並且它們應與位元運算子(如位元 OR `|`)一起作為位元值使用。除非另有說明,否則應認為列舉型別是可擴充的。

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

對於由 Node-API 函數回傳或作為 Node-API 函數輸出參數提供的列舉型別,該值是一個整數值,附加元件應處理未知的值。新的值可以在沒有版本防護 (version guard) 的情況下引入。例如,在 switch 陳述式中檢查 napi_status 時,附加元件應包含一個 default 分支,因為較新的 Node.js 版本可能會引入新的狀態碼。

對於用於輸入參數的列舉型別,除非另有說明,否則將未知整數值傳遞給 Node-API 函數的結果是未定義的。新值會加上版本防護,以指示引入該值的 Node-API 版本。例如,napi_get_all_property_names 可以擴充新的 napi_key_filter 列舉值。

對於同時用於輸入參數和輸出參數的列舉型別,允許在沒有版本防護的情況下引入新值。

建置#

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

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

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

xcode-select --install

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

npm install --global windows-build-tools

以下章節介紹了用於開發和部署 Node.js 原生附加元件的其他工具。

建置工具#

這裡列出的兩種工具都要求原生附加元件的「使用者」必須安裝 C/C++ 工具鏈,才能成功安裝原生附加元件。

node-gyp#

node-gyp 是一個基於 Google GYP 工具的 gyp-next 分支的建置系統,並隨 npm 一起打包。GYP(因此 node-gyp)需要安裝 Python。

歷史上,node-gyp 一直是建置原生附加元件的首選工具。它已被廣泛採用並擁有完整的說明文件。然而,一些開發人員遇到了 node-gyp 的限制。

CMake.js#

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

對於已經使用 CMake 的專案或受到 node-gyp 限制影響的開發人員來說,CMake.js 是一個不錯的選擇。build_with_cmake 是一個基於 CMake 的原生附加元件專案範例。

上傳預編譯二進位檔#

此處列出的三種工具允許原生附加元件開發人員和維護人員建立並上傳二進位檔到公開或私有伺服器。這些工具通常與 CI/CD 建置系統(如 Travis CIAppVeyor)整合,以針對各種平台和架構建置並上傳二進位檔。這些二進位檔隨後可供無需安裝 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 的實驗性功能的名稱。

Node-API 版本矩陣#

直到第 9 版,Node-API 版本都是累加的,且獨立於 Node.js 進行版本控制。這意味著任何版本都是對前一個版本的擴充,它具有前一個版本的所有 API 以及一些新增內容。每個 Node.js 版本僅支援單一 Node-API 版本。例如,v18.15.0 僅支援 Node-API 版本 8。ABI 穩定性得以實現,因為 8 是所有先前版本的嚴格超集合。

從第 9 版開始,雖然 Node-API 版本繼續獨立進行版本控制,但執行 Node-API 版本 9 的附加元件可能需要進行程式碼更新才能在 Node-API 版本 10 上執行。然而,ABI 穩定性得以維持,因為支援高於 8 之 Node-API 版本的 Node.js 版本將支援 8 與其所支援的最高版本之間的所有版本,並預設提供版本 8 API,除非附加元件選擇啟用更高的 Node-API 版本。這種方法提供了更好地最佳化現有 Node-API 函數的靈活性,同時保持 ABI 穩定性。現有的附加元件可以繼續使用舊版本的 Node-API 執行而無需重新編譯。如果附加元件需要新 Node-API 版本的功能,無論如何都需要修改現有程式碼並重新編譯才能使用這些新函數。

在支援 Node-API 版本 9 及更高版本的 Node.js 版本中,定義 NAPI_VERSION=X 並使用現有的附加元件初始化巨集,會將執行時期所需的 Node-API 版本寫入附加元件中。如果未設定 NAPI_VERSION,則預設為 8。

此表格在舊版流中可能已過期,最新資訊請參閱最新的 API 文件:Node-API 版本矩陣

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

* Node-API 為實驗性功能。

** Node.js 8.0.0 將 Node-API 納入為實驗性功能。它作為 Node-API 版本 1 發布,但持續演進直到 Node.js 8.6.0。Node.js 8.6.0 之前的版本 API 不同。我們建議使用 Node-API 版本 3 或更高版本。

為 Node-API 記錄的每個 API 都會有一個名為 added in: 的標頭,而穩定的 API 將會有額外的 Node-API version: 標頭。當使用支援 Node-API version: 所示版本或更高版本的 Node.js 版本時,API 可直接使用。當使用不支援所列 Node-API version: 的 Node.js 版本,或未列出 Node-API version: 時,只有在 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 語言規範的 Agent 章節將「Agent」的概念定義為執行 JavaScript 程式碼的自包含環境。處理序可以同時或依序啟動並終止多個此類 Agent。

一個 Node.js 環境對應於一個 ECMAScript Agent。在主處理序中,環境在啟動時建立,並且可以在單獨的執行緒上建立額外的環境以作為工作執行緒 (worker threads)。當 Node.js 嵌入到另一個應用程式中時,應用程式的主執行緒也可能在應用程式處理序的生命週期內多次建構和銷毀 Node.js 環境,使得應用程式建立的每個 Node.js 環境,在其生命週期內,也可能輪流作為工作執行緒建立和銷毀額外的環境。

從原生附加元件的角度來看,這意味著它提供的綁定可能會被多次呼叫,從多個內容 (contexts) 呼叫,甚至同時從多個執行緒呼叫。

原生附加元件可能需要在其 Node.js 環境的生命週期中分配全域狀態,以便該狀態對於附加元件的每個實例都是唯一的。

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

napi_set_instance_data#

napi_status napi_set_instance_data(node_api_basic_env env,
                                   void* data,
                                   napi_finalize finalize_cb,
                                   void* finalize_hint);
  • [in] env:呼叫 Node-API 時所在的環境。
  • [in] data:可供此實例的綁定使用的資料項目。
  • [in] finalize_cb:環境被銷毀時要呼叫的函數。該函數接收 data,以便將其釋放。napi_finalize 提供了更多詳細資訊。
  • [in] finalize_hint:在收集過程中傳遞給終結回呼的可選提示。

如果 API 成功,則回傳 napi_ok

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

napi_get_instance_data#

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

如果 API 成功,則回傳 napi_ok

此 API 檢索先前透過 napi_set_instance_data() 與目前正在執行的 Node.js 環境關聯的資料。如果未設定任何資料,呼叫將成功,且 data 將被設定為 NULL

基本 Node-API 資料型別#

Node-API 將以下基礎資料型別作為各類 API 所消耗的抽象暴露出來。這些 API 應被視為不透明的,僅能透過其他 Node-API 呼叫進行檢查。

napi_status#

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

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

如果 API 回傳失敗狀態後需要更多資訊,可以透過呼叫 napi_get_last_error_info 取得。

napi_extended_error_info#

typedef struct {
  const char* error_message;
  void* engine_reserved;
  uint32_t engine_error_code;
  napi_status error_code;
} napi_extended_error_info;
  • error_message:包含 VM 無關錯誤描述的 UTF8 編碼字串。
  • engine_reserved:為 VM 特定的錯誤詳細資訊保留。目前未針對任何 VM 實作。
  • engine_error_code:VM 特定的錯誤碼。目前未針對任何 VM 實作。
  • error_code:源自最後一個錯誤的 Node-API 狀態碼。

請參閱 錯誤處理章節以取得更多資訊。

napi_env#

napi_env 用於表示底層 Node-API 實作可用於持久化 VM 特定狀態的內容。此結構在呼叫原生函數時傳遞給它們,並且在進行 Node-API 呼叫時必須傳回。具體而言,在呼叫初始原生函數時傳入的同一個 napi_env 必須傳遞給任何後續的嵌套 Node-API 呼叫。不允許快取 napi_env 以進行通用重用,也不允許在執行於不同 Worker 執行緒上的相同附加元件實例之間傳遞 napi_env。當原生附加元件實例被卸載時,napi_env 將失效。此事件的通知透過傳遞給 napi_add_env_cleanup_hooknapi_set_instance_data 的回呼來傳遞。

node_api_basic_env#

穩定性:1 - 實驗性

napi_env 的變體被傳遞給同步終結器 (node_api_basic_finalize)。有一部分 Node-API 接受 node_api_basic_env 型別的參數作為其第一個參數。這些 API 不會存取 JavaScript 引擎的狀態,因此可以安全地從同步終結器中呼叫。允許將 napi_env 型別的參數傳遞給這些 API,但是不允許將 node_api_basic_env 型別的參數傳遞給存取 JavaScript 引擎狀態的 API。當以導致錯誤指標傳遞給函數時會觸發警告或錯誤的旗標編譯附加元件時,嘗試這樣做而未經轉型將產生編譯器警告或錯誤。從同步終結器中呼叫此類 API 最終會導致應用程式終止。

napi_value#

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

napi_threadsafe_function#

這是一個不透明指標,表示一個可以透過 napi_call_threadsafe_function() 從多個執行緒非同步呼叫的 JavaScript 函數。

napi_threadsafe_function_release_mode#

傳遞給 napi_release_threadsafe_function() 的值,用於指示執行緒安全函數是應立即關閉 (napi_tsfn_abort) 還是僅釋放 (napi_tsfn_release),從而可透過 napi_acquire_threadsafe_function()napi_call_threadsafe_function() 進行後續使用。

typedef enum {
  napi_tsfn_release,
  napi_tsfn_abort
} napi_threadsafe_function_release_mode;

napi_threadsafe_function_call_mode#

傳遞給 napi_call_threadsafe_function() 的值,用於指示當與執行緒安全函數關聯的佇列已滿時,呼叫是否應阻塞。

typedef enum {
  napi_tsfn_nonblocking,
  napi_tsfn_blocking
} napi_threadsafe_function_call_mode;

Node-API 記憶體管理型別#

napi_handle_scope#

這是一種用於控制和修改在特定範圍內建立的物件生命週期的抽象。通常,Node-API 值是在控制代碼範圍 (handle scope) 的內容中建立的。當從 JavaScript 呼叫原生方法時,會存在一個預設的控制代碼範圍。如果使用者沒有明確建立新的控制代碼範圍,Node-API 值將在預設的控制代碼範圍內建立。對於原生方法執行之外的任何程式碼呼叫(例如在 libuv 回呼呼叫期間),模組需要在呼叫任何可能導致建立 JavaScript 值的函數之前建立一個範圍。

控制代碼範圍使用 napi_open_handle_scope 建立,並使用 napi_close_handle_scope 銷毀。關閉範圍可以向 GC 指示,在控制代碼範圍生命週期內建立的所有 napi_value 不再從目前的堆疊框架中被參照。

如需更多詳細資訊,請查看物件生命週期管理

napi_escapable_handle_scope#

可逸出控制代碼範圍 (Escapable handle scopes) 是一種特殊的控制代碼範圍,用於將特定控制代碼範圍內建立的值回傳給父範圍。

napi_ref#

這是用於參照 napi_value 的抽象。這允許使用者管理 JavaScript 值的生命週期,包括明確定義它們的最小生命週期。

如需更多詳細資訊,請查看物件生命週期管理

napi_type_tag#

一個儲存為兩個無符號 64 位元整數的 128 位元值。它作為 UUID,JavaScript 物件或外部 (externals) 可以用它來「標記」,以確保它們屬於特定型別。這比 napi_instanceof 更嚴格,因為後者如果物件的原型已被操縱,可能會報告誤報。型別標記 (Type-tagging) 與 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:由次要執行緒建立的資料。將此原生資料轉換為可在呼叫 js_callback 時作為參數傳遞的 JavaScript 值(使用 Node-API 函數)是回呼的責任。此指標完全由執行緒和此回呼管理。因此,此回呼應負責釋放該資料。

除非有物件生命週期管理中討論的原因,否則在函數主體內建立控制代碼和/或回呼範圍是不必要的。

napi_cleanup_hook#

napi_add_env_cleanup_hook 一起使用的函數指標。當環境被拆除時,它將被呼叫。

回呼函數必須滿足以下簽章:

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

napi_add_async_cleanup_hook 一起使用的函數指標。當環境被拆除時,它將被呼叫。

回呼函數必須滿足以下簽章:

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

函數的主體應啟動非同步清理操作,在其結束時必須透過呼叫 napi_remove_async_cleanup_hook 傳入 handle

錯誤處理#

Node-API 使用回傳值和 JavaScript 例外狀況進行錯誤處理。以下章節解釋了每種情況的方法。

回傳值#

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

如果請求成功且沒有拋出未捕獲的 JavaScript 例外狀況,則回傳值將為 napi_ok。如果發生錯誤且拋出了例外狀況,將回傳錯誤的 napi_status 值。如果拋出了例外狀況,但沒有發生錯誤,將回傳 napi_pending_exception

在回傳 napi_oknapi_pending_exception 以外的回傳值的情況下,必須呼叫 napi_is_exception_pending 以檢查是否有例外狀況掛起。有關更多詳細資訊,請參閱例外狀況章節。

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

napi_status 回傳值提供了所發生錯誤的與 VM 無關的表示。在某些情況下,能夠取得更詳細的資訊(包括表示錯誤的字串以及 VM (引擎) 特定的資訊)會很有用。

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

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

napi_get_last_error_info 回傳最後一次執行的 Node-API 呼叫的資訊。

請勿依賴任何擴充資訊的內容或格式,因為它不受 SemVer 約束,可能會隨時變更。它僅用於記錄目的。

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

如果 API 成功,則回傳 napi_ok

此 API 檢索包含有關最後發生錯誤的資訊的 napi_extended_error_info 結構。

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

請勿依賴任何擴充資訊的內容或格式,因為它不受 SemVer 約束,可能會隨時變更。它僅用於記錄目的。

即使有掛起的 JavaScript 例外狀況,也可以呼叫此 API。

例外狀況#

任何 Node-API 函數呼叫都可能導致掛起的 JavaScript 例外狀況。對於任何 API 函數都是如此,即使是那些可能不會導致 JavaScript 執行的函數。

如果函數回傳的 napi_statusnapi_ok,則沒有掛起的例外狀況,無需採取額外行動。如果回傳的 napi_status 是除 napi_oknapi_pending_exception 以外的任何值,為了嘗試恢復並繼續而不是直接回傳,必須呼叫 napi_is_exception_pending 以確定是否有例外狀況掛起。

在許多情況下,當呼叫 Node-API 函數且已有例外狀況掛起時,該函數將立即回傳 napi_pending_exceptionnapi_status。然而,並非所有函數都是這樣。Node-API 允許呼叫一組子集函數,以便在回傳 JavaScript 之前進行一些最小的清理。在這種情況下,napi_status 將反映函數的狀態。它不會反映先前掛起的例外狀況。為避免混淆,請在每次函數呼叫後檢查錯誤狀態。

當例外狀況掛起時,可以採用以下兩種方法之一。

第一種方法是進行任何適當的清理,然後回傳,以便執行恢復到 JavaScript。作為回到 JavaScript 轉換的一部分,例外狀況將在原生方法被呼叫的 JavaScript 程式碼位置處拋出。當例外狀況掛起時,大多數 Node-API 呼叫的行為是未定義的,許多會直接回傳 napi_pending_exception,因此盡可能少做處理,然後回到可以處理例外狀況的 JavaScript。

第二種方法是嘗試處理例外狀況。在某些情況下,原生程式碼可以捕獲例外狀況,採取適當的行動,然後繼續執行。僅建議在已知可以安全處理例外狀況的特定情況下使用此方法。在這些情況下,可以使用 napi_get_and_clear_last_exception 來取得並清除例外狀況。成功後,result 將包含最後拋出的 JavaScript Object 的控制代碼。如果確定在檢索例外狀況後,例外狀況終究無法處理,可以使用 napi_throw 將其重新拋出,其中 error 是要拋出的 JavaScript 值。

如果原生程式碼需要拋出例外狀況或確定 napi_value 是否為 JavaScript Error 物件的實例,還可以使用以下公用程式函數:napi_throw_error, napi_throw_type_error, napi_throw_range_error, node_api_throw_syntax_errornapi_is_error

如果原生程式碼需要建立 Error 物件,還可以使用以下公用程式函數:napi_create_error, napi_create_type_error, napi_create_range_errornode_api_create_syntax_error,其中 result 是指向新建立的 JavaScript Error 物件的 napi_value

Node.js 專案正在為所有內部產生的錯誤新增錯誤碼。目標是讓應用程式使用這些錯誤碼進行所有錯誤檢查。相關的錯誤訊息將保留,但僅用於記錄和顯示,並預期訊息可能會在沒有套用 SemVer 的情況下變更。為了在 Node-API 中支援此模型,無論是在內部功能還是在模組特定功能中(這是一個好習慣),throw_create_ 函數都會採用一個可選的 code 參數,該參數是要新增到錯誤物件中的程式碼字串。如果可選參數為 NULL,則不會有程式碼與該錯誤關聯。如果提供了程式碼,與錯誤關聯的名稱也會更新為:

originalName [code]

其中 originalName 是與錯誤關聯的原始名稱,code 是提供的程式碼。例如,如果程式碼為 'ERR_ERROR_1' 且正在建立一個 TypeError,名稱將為:

TypeError [ERR_ERROR_1]
napi_throw#
NAPI_EXTERN napi_status napi_throw(napi_env env, napi_value error);
  • [in] env:API 呼叫所在的環境。
  • [in] error:要拋出的 JavaScript 值。

如果 API 成功,則回傳 napi_ok

此 API 拋出所提供的 JavaScript 值。

napi_throw_error#
NAPI_EXTERN napi_status napi_throw_error(napi_env env,
                                         const char* code,
                                         const char* msg);
  • [in] env:API 呼叫所在的環境。
  • [in] code:要設定在錯誤上的可選錯誤碼。
  • [in] msg:表示要與錯誤關聯的文字的 C 字串。

如果 API 成功,則回傳 napi_ok

此 API 拋出一個帶有所提供文字的 JavaScript Error

napi_throw_type_error#
NAPI_EXTERN napi_status napi_throw_type_error(napi_env env,
                                              const char* code,
                                              const char* msg);
  • [in] env:API 呼叫所在的環境。
  • [in] code:要設定在錯誤上的可選錯誤碼。
  • [in] msg:表示要與錯誤關聯的文字的 C 字串。

如果 API 成功,則回傳 napi_ok

此 API 拋出一個帶有所提供文字的 JavaScript TypeError

napi_throw_range_error#
NAPI_EXTERN napi_status napi_throw_range_error(napi_env env,
                                               const char* code,
                                               const char* msg);
  • [in] env:API 呼叫所在的環境。
  • [in] code:要設定在錯誤上的可選錯誤碼。
  • [in] msg:表示要與錯誤關聯的文字的 C 字串。

如果 API 成功,則回傳 napi_ok

此 API 拋出一個帶有所提供文字的 JavaScript RangeError

node_api_throw_syntax_error#
NAPI_EXTERN napi_status node_api_throw_syntax_error(napi_env env,
                                                    const char* code,
                                                    const char* msg);
  • [in] env:API 呼叫所在的環境。
  • [in] code:要設定在錯誤上的可選錯誤碼。
  • [in] msg:表示要與錯誤關聯的文字的 C 字串。

如果 API 成功,則回傳 napi_ok

此 API 拋出一個帶有所提供文字的 JavaScript SyntaxError

napi_is_error#
NAPI_EXTERN napi_status napi_is_error(napi_env env,
                                      napi_value value,
                                      bool* result);
  • [in] env:API 呼叫所在的環境。
  • [in] value:要檢查的 napi_value
  • [out] result:如果 napi_value 表示錯誤,則設定為 true 的布林值,否則為 false。

如果 API 成功,則回傳 napi_ok

此 API 查詢 napi_value 以檢查它是否表示一個錯誤物件。

napi_create_error#
NAPI_EXTERN napi_status napi_create_error(napi_env env,
                                          napi_value code,
                                          napi_value msg,
                                          napi_value* result);
  • [in] env:API 呼叫所在的環境。
  • [in] code:帶有要與錯誤關聯的錯誤碼字串的可選 napi_value
  • [in] msg:參照 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 支援「可逸出範圍 (escapable scope)」以支援這種情況。可逸出範圍允許將一個控制代碼「提升」,以便它「逸出」目前的範圍,並且控制代碼的存活期從目前的範圍變更為外部範圍的存活期。

可用於開啟/關閉可逸出範圍的方法有 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 僅允許為有限的一組值型別建立參照,包括 object、external、function 和 symbol。

每個參照都有一個關聯的計數(值為 0 或更高),該計數決定了該參照是否會使相應的值保持存活。計數為 0 的參照不會阻止值被收集。Object(object、function、external)和 symbol 型別的值會變成「弱」參照,並且在它們未被收集時仍然可以存取。任何大於 0 的計數都會防止這些值被收集。

Symbol 值有不同的類型。真正的弱參照語義僅由使用 napi_create_symbol 函數或 JavaScript Symbol() 建構函式呼叫建立的本地 symbol 支援。使用 node_api_symbol_for 函數或 JavaScript Symbol.for() 函數呼叫建立的全域註冊 symbol 始終保持強參照,因為垃圾收集器不會收集它們。對於眾所周知的 symbol(例如 Symbol.iterator)也是如此。它們也永遠不會被垃圾收集器收集。

參照可以用初始參照計數建立。然後可以透過 napi_reference_refnapi_reference_unref 修改該計數。如果物件在參照計數為 0 時被收集,則後續所有取得與該參照關聯物件的呼叫(napi_get_reference_value)都將回傳 NULL 作為回傳的 napi_value。嘗試對物件已被收集的參照呼叫 napi_reference_ref 會導致錯誤。

參照必須在附加元件不再需要它們時被刪除。刪除參照後,它將不再阻止相應物件被收集。未能刪除持久參照會導致「記憶體洩漏」,持久參照的原生記憶體和堆疊上的相應物件都將永遠保留。

可以建立指向相同物件的多個持久參照,每個參照將根據其個別計數使物件保持存活或不保持存活。對相同物件的多個持久參照可能會導致意外地使原生記憶體保持存活。持久參照的原生結構必須保持存活,直到所參照物件的終結器執行為止。如果為相同物件建立了新的持久參照,該物件的終結器將不會執行,並且先前持久參照所指向的原生記憶體將不會被釋放。這可以透過在可能的情況下除了呼叫 napi_reference_unref 之外還呼叫 napi_delete_reference 來避免。

變更歷史

  • 版本 10 (NAPI_VERSION 定義為 10 或更高)

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

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

如果 API 成功,則回傳 napi_ok

此 API 以指定的參照計數為傳入的值建立一個新參照。

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

如果 API 成功,則回傳 napi_ok

此 API 刪除傳入的參照。

即使有掛起的 JavaScript 例外狀況,也可以呼叫此 API。

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

如果 API 成功,則回傳 napi_ok

此 API 遞增傳入參照的參照計數並回傳結果參照計數。

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

如果 API 成功,則回傳 napi_ok

此 API 遞減傳入參照的參照計數並回傳結果參照計數。

napi_get_reference_value#
NAPI_EXTERN napi_status napi_get_reference_value(napi_env env,
                                                 napi_ref ref,
                                                 napi_value* result);
  • [in] env:API 呼叫所在的環境。
  • [in] ref:請求相應值的 napi_ref
  • [out] result:由 napi_ref 參照的 napi_value

如果 API 成功,則回傳 napi_ok

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

Node.js 環境退出時的清理#

雖然 Node.js 處理序通常在退出時釋放其所有資源,但 Node.js 的嵌入者或未來的 Worker 支援,可能要求附加元件註冊在目前 Node.js 環境退出時將執行的清理掛鉤。

Node-API 提供了註冊和取消註冊此類回呼的函數。當這些回呼執行時,附加元件持有的所有資源都應被釋放。

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

註冊 fun 作為在目前 Node.js 環境退出時將與 arg 參數一起執行的函數。

一個函數可以安全地指定多次,並使用不同的 arg 值。在這種情況下,它也會被呼叫多次。不允許多次提供相同的 funarg 值,這將導致處理序中止。

掛鉤將以相反順序呼叫,即最後新增的掛鉤將最先呼叫。

可以透過使用 napi_remove_env_cleanup_hook 來移除此掛鉤。通常,這發生在為其新增此掛鉤的資源被拆除時。

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

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

取消註冊 fun 作為在目前 Node.js 環境退出時將與 arg 參數一起執行的函數。參數和函數值都需要完全相符。

該函數必須最初使用 napi_add_env_cleanup_hook 註冊,否則處理序將中止。

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

註冊 hook,這是一個型別為 napi_async_cleanup_hook 的函式,作為當前 Node.js 環境退出時,使用 remove_handlearg 參數來執行的函式。

napi_add_env_cleanup_hook 不同,此 hook 允許是非同步的。

除此以外,其行為通常與 napi_add_env_cleanup_hook 一致。

如果 remove_handle 不是 NULL,則會在其中儲存一個不透明值,該值稍後必須傳遞給 napi_remove_async_cleanup_hook,無論該 hook 是否已被呼叫。通常,當添加此 hook 的資源被銷毀時,就會發生這種情況。

napi_remove_async_cleanup_hook#
NAPI_EXTERN napi_status napi_remove_async_cleanup_hook(
    napi_async_cleanup_hook_handle remove_handle);

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

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

Node.js 環境可能會在任何時間盡快被銷毀,且禁止執行 JavaScript,例如在收到 worker.terminate() 請求時。當環境正在銷毀時,JavaScript 物件、執行緒安全函式和環境實例資料已註冊的 napi_finalize 回呼會立即且獨立地被呼叫。

napi_finalize 回呼的呼叫時程安排在手動註冊的清理 hook 之後。為了確保環境關閉期間插件終結的正確順序,以避免在 napi_finalize 回呼中出現釋放後使用(use-after-free)的情況,插件應使用 napi_add_env_cleanup_hooknapi_add_async_cleanup_hook 註冊清理 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;
}

若要定義一個類別以便可以建立新實例(通常與 物件封裝 (Object wrap) 一起使用)

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

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

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

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

  return exports;
}

您也可以使用 NAPI_MODULE_INIT 巨集,它是 NAPI_MODULE 和定義 Init 函式的簡寫

NAPI_MODULE_INIT(/* napi_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 插件都是「上下文感知 (context-aware)」的,這意味著它們可能會被載入多次。宣告此類模組時有一些設計考量。上下文感知插件 的文件提供了更多詳細資訊。

變數 envexports 將在巨集呼叫後的函式本體內可用。

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

關於建構插件模組的更多一般資訊,請參考現有的 API。

處理 JavaScript 值#

Node-API 暴露了一組 API 來建立所有類型的 JavaScript 值。其中一些類型記錄在 ECMAScript 語言規範語言類型 (language types) 節 中。

從根本上說,這些 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 類型。

列舉類型 (Enum types)#

napi_key_collection_mode#
typedef enum {
  napi_key_include_prototypes,
  napi_key_own_only
} napi_key_collection_mode;

描述 Keys/Properties 過濾列舉

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

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

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

屬性過濾位元旗標。這可以配合位元運算子來建構複合過濾器。

napi_key_conversion#
typedef enum {
  napi_key_keep_numbers,
  napi_key_numbers_to_strings
} napi_key_conversion;

napi_key_numbers_to_strings 會將整數索引轉換為字串。napi_key_keep_numbers 會針對整數索引回傳數字。

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

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

napi_external 類型的 JavaScript 值在 JavaScript 中顯示為一個普通物件,因此不能在其上設定任何屬性,也沒有原型。

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

這代表 TypedArray 底層的二進位純量資料類型。此列舉的元素對應於 ECMAScript 語言規範TypedArray 物件節

物件建立函式#

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

如果 API 成功,則回傳 napi_ok

此 API 回傳對應於 JavaScript Array 類型的 Node-API 值。JavaScript 陣列描述於 ECMAScript 語言規範的 Array 物件節

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

如果 API 成功,則回傳 napi_ok

此 API 回傳對應於 JavaScript Array 類型的 Node-API 值。Arraylength 屬性被設定為傳入的長度參數。然而,VM 在建立陣列時並不保證底層緩衝區會被預先分配。該行為留給底層 VM 實作決定。如果緩衝區必須是可直接透過 C 讀取和/或寫入的連續記憶體區塊,請考慮使用 napi_create_external_arraybuffer

JavaScript 陣列描述於 ECMAScript 語言規範的 Array 物件節

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

如果 API 成功,則回傳 napi_ok

此 API 回傳對應於 JavaScript ArrayBuffer 的 Node-API 值。ArrayBuffer 用於代表固定長度的二進位資料緩衝區。它們通常用作 TypedArray 物件的後備緩衝區。所分配的 ArrayBuffer 將具有底層位元組緩衝區,其大小由傳入的 length 參數決定。底層緩衝區可選擇性地回傳給呼叫者,以供呼叫者直接操作該緩衝區。此緩衝區只能由原生程式碼直接寫入。若要從 JavaScript 寫入此緩衝區,需要建立 TypedArray 或 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: 指向底層緩衝區的原始指標。data 可以選擇性地透過傳遞 NULL 來忽略。
  • [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 底層資料緩衝區的指標。result_data 可以選擇性地透過傳遞 NULL 來忽略。
  • [out] result: 代表 node::Buffernapi_value

如果 API 成功,則回傳 napi_ok

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

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

如果 API 成功,則回傳 napi_ok

此 API 不會考慮閏秒;它們會被忽略,因為 ECMAScript 與 POSIX 時間規範對齊。

此 API 分配一個 JavaScript Date 物件。

JavaScript Date 物件描述於 ECMAScript 語言規範的 Date 物件節

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

如果 API 成功,則回傳 napi_ok

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

該 API 新增了一個 napi_finalize 回呼,當剛剛建立的 JavaScript 物件被垃圾回收時,該回呼將被呼叫。

建立的值不是物件,因此不支援額外屬性。它被視為一種不同的值類型:對一個外部值呼叫 napi_typeof() 會得到 napi_external

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

如果 API 成功,則回傳 napi_ok

除了 Node.js 之外,一些執行環境已放棄對外部緩衝區的支援。在 Node.js 以外的執行環境中,此方法可能會回傳 napi_no_external_buffers_allowed,表示不支援外部緩衝區。Electron 就是這樣的一個執行環境,如該問題所述 electron/issues/35801

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

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

該 API 新增了一個 napi_finalize 回呼,當剛剛建立的 JavaScript 物件被垃圾回收時,該回呼將被呼叫。

JavaScript ArrayBuffer 描述於 ECMAScript 語言規範的 ArrayBuffer 物件節

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

如果 API 成功,則回傳 napi_ok

除了 Node.js 之外,一些執行環境已放棄對外部緩衝區的支援。在 Node.js 以外的執行環境中,此方法可能會回傳 napi_no_external_buffers_allowed,表示不支援外部緩衝區。Electron 就是這樣的一個執行環境,如該問題所述 electron/issues/35801

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

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

該 API 新增了一個 napi_finalize 回呼,當剛剛建立的 JavaScript 物件被垃圾回收時,該回呼將被呼叫。

對於 Node.js >=4,BuffersUint8Array

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

如果 API 成功,則回傳 napi_ok

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

JavaScript Object 類型描述於 ECMAScript 語言規範的 物件類型節

node_api_create_object_with_properties#

穩定性:1 - 實驗性

napi_status node_api_create_object_with_properties(napi_env env,
                                                   napi_value prototype_or_null,
                                                   const napi_value* property_names,
                                                   const napi_value* property_values,
                                                   size_t property_count,
                                                   napi_value* result)
  • [in] env:API 呼叫所在的環境。
  • [in] prototype_or_null: 新物件的原型物件。可以是代表 JavaScript 物件的 napi_value 以用作原型,代表 JavaScript nullnapi_value,或是將被轉換為 nullnullptr
  • [in] property_names: 代表屬性名稱的 napi_value 陣列。
  • [in] property_values: 代表屬性值的 napi_value 陣列。
  • [in] property_count: 陣列中的屬性數量。
  • [out] result: 代表 JavaScript Objectnapi_value

如果 API 成功,則回傳 napi_ok

此 API 使用指定的原型和屬性建立 JavaScript Object。這比呼叫 napi_create_object 後再多次呼叫 napi_set_property 更有效率,因為它可以原子方式建立帶有所有屬性的物件,從而避免潛在的 V8 map 轉換。

陣列 property_namesproperty_values 必須具有由 property_count 指定的相同長度。屬性會按照它們在陣列中出現的順序添加到物件中。

napi_create_symbol#
napi_status napi_create_symbol(napi_env env,
                               napi_value description,
                               napi_value* result)
  • [in] env:API 呼叫所在的環境。
  • [in] description: 選擇性的 napi_value,指向要設定為該符號描述的 JavaScript string
  • [out] result: 代表 JavaScript symbolnapi_value

如果 API 成功,則回傳 napi_ok

此 API 從 UTF8 編碼的 C 字串建立 JavaScript symbol 值。

JavaScript symbol 類型描述於 ECMAScript 語言規範的 符號類型節

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 語言規範的 符號類型節

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: TypedArray 的底層 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 的底層 ArrayBufferSharedArrayBuffer
  • [in] byte_offset: ArrayBuffer 內的位元組偏移量,從該處開始映射 DataView
  • [out] result: 代表 JavaScript DataViewnapi_value

如果 API 成功,則回傳 napi_ok

此 API 在現有的 ArrayBufferSharedArrayBuffer 上建立 JavaScript DataView 物件。DataView 物件在底層資料緩衝區上提供了一種類似陣列的檢視,但允許在 ArrayBufferSharedArrayBuffer 中使用不同大小和類型的項目。

必須滿足 byte_length + byte_offset 小於或等於傳入陣列的大小(位元組)。如果不滿足,將拋出 RangeError 例外。

JavaScript DataView 物件描述於 ECMAScript 語言規範的 DataView 物件節

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

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

如果 API 成功,則回傳 napi_ok

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

JavaScript number 類型描述於 ECMAScript 語言規範的 數字類型節

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

如果 API 成功,則回傳 napi_ok

此 API 用於將 C uint32_t 類型轉換為 JavaScript number 類型。

JavaScript number 類型描述於 ECMAScript 語言規範的 數字類型節

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

如果 API 成功,則回傳 napi_ok

此 API 用於將 C int64_t 類型轉換為 JavaScript number 類型。

JavaScript number 類型描述於 ECMAScript 語言規範的 數字類型節。請注意,int64_t 的完整範圍無法在 JavaScript 中以完全精確的方式表示。超出 Number.MIN_SAFE_INTEGER -(2**53 - 1)Number.MAX_SAFE_INTEGER (2**53 - 1) 範圍的整數值將會失去精度。

napi_create_double#
napi_status napi_create_double(napi_env env, double value, napi_value* result)
  • [in] env:API 呼叫所在的環境。
  • [in] value: 要在 JavaScript 中表示的雙精確度浮點值。
  • [out] result: 代表 JavaScript numbernapi_value

如果 API 成功,則回傳 napi_ok

此 API 用於將 C double 類型轉換為 JavaScript number 類型。

JavaScript number 類型描述於 ECMAScript 語言規範的 數字類型節

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

如果 API 成功,則回傳 napi_ok

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

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

如果 API 成功,則回傳 napi_ok

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

napi_create_bigint_words#
napi_status napi_create_bigint_words(napi_env env,
                                     int sign_bit,
                                     size_t word_count,
                                     const uint64_t* words,
                                     napi_value* result);
  • [in] env:API 呼叫所在的環境。
  • [in] sign_bit: 決定產生的 BigInt 是正數還是負數。
  • [in] word_count: words 陣列的長度。
  • [in] words: 一個 uint64_t 小端序 64 位元字的陣列。
  • [out] result: 代表 JavaScript BigIntnapi_value

如果 API 成功,則回傳 napi_ok

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

產生的 BigInt 計算方式為:(–1)sign_bit (words[0] × (264)0 + words[1] × (264)1 + …)

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

如果 API 成功,則回傳 napi_ok

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

JavaScript string 類型描述於 ECMAScript 語言規範的 字串類型節

node_api_create_external_string_latin1#
napi_status
node_api_create_external_string_latin1(napi_env env,
                                       char* str,
                                       size_t length,
                                       napi_finalize finalize_callback,
                                       void* finalize_hint,
                                       napi_value* result,
                                       bool* copied);
  • [in] env:API 呼叫所在的環境。
  • [in] str: 代表 ISO-8859-1 編碼字串的字元緩衝區。
  • [in] length: 字串長度(位元組),如果它是 null 結尾的字串,則為 NAPI_AUTO_LENGTH
  • [in] finalize_callback: 字串被回收時要呼叫的函式。該函式將以以下參數呼叫
    • [in] env: 插件執行所在的環境。如果字串作為 worker 或 Node.js 主實例終止的一部分被回收,此值可能為 null。
    • [in] data: 這是 strvoid* 指標值。
    • [in] finalize_hint: 這是傳遞給 API 的 finalize_hint 值。napi_finalize 提供了更多詳細資訊。此參數是選擇性的。傳遞 null 值表示插件不需要在對應的 JavaScript 字串被回收時收到通知。
  • [in] finalize_hint:在收集過程中傳遞給終結回呼的可選提示。
  • [out] result: 代表 JavaScript stringnapi_value
  • [out] copied: 字串是否被複製。如果已複製,終結處理器將已被呼叫以銷毀 str

如果 API 成功,則回傳 napi_ok

此 API 從 ISO-8859-1 編碼的 C 字串建立 JavaScript string 值。原生字串可能不會被複製,因此必須在 JavaScript 值的整個生命週期內保持有效。

JavaScript string 類型描述於 ECMAScript 語言規範的 字串類型節

napi_create_string_utf16#
napi_status napi_create_string_utf16(napi_env env,
                                     const char16_t* str,
                                     size_t length,
                                     napi_value* result)
  • [in] env:API 呼叫所在的環境。
  • [in] str: 代表 UTF16-LE 編碼字串的字元緩衝區。
  • [in] length: 字串長度(以雙位元組程式碼單元計算),如果它是 null 結尾的字串,則為 NAPI_AUTO_LENGTH
  • [out] result: 代表 JavaScript stringnapi_value

如果 API 成功,則回傳 napi_ok

此 API 從 UTF16-LE 編碼的 C 字串建立 JavaScript string 值。原生字串會被複製。

JavaScript string 類型描述於 ECMAScript 語言規範的 字串類型節

node_api_create_external_string_utf16#
napi_status
node_api_create_external_string_utf16(napi_env env,
                                      char16_t* str,
                                      size_t length,
                                      napi_finalize finalize_callback,
                                      void* finalize_hint,
                                      napi_value* result,
                                      bool* copied);
  • [in] env:API 呼叫所在的環境。
  • [in] str: 代表 UTF16-LE 編碼字串的字元緩衝區。
  • [in] length: 字串長度(以雙位元組程式碼單元計算),如果它是 null 結尾的字串,則為 NAPI_AUTO_LENGTH
  • [in] finalize_callback: 字串被回收時要呼叫的函式。該函式將以以下參數呼叫
    • [in] env: 插件執行所在的環境。如果字串作為 worker 或 Node.js 主實例終止的一部分被回收,此值可能為 null。
    • [in] data: 這是 strvoid* 指標值。
    • [in] finalize_hint: 這是傳遞給 API 的 finalize_hint 值。napi_finalize 提供了更多詳細資訊。此參數是選擇性的。傳遞 null 值表示插件不需要在對應的 JavaScript 字串被回收時收到通知。
  • [in] finalize_hint:在收集過程中傳遞給終結回呼的可選提示。
  • [out] result: 代表 JavaScript stringnapi_value
  • [out] copied: 字串是否被複製。如果已複製,終結處理器將已被呼叫以銷毀 str

如果 API 成功,則回傳 napi_ok

此 API 從 UTF16-LE 編碼的 C 字串建立 JavaScript string 值。原生字串可能不會被複製,因此必須在 JavaScript 值的整個生命週期內保持有效。

JavaScript string 類型描述於 ECMAScript 語言規範的 字串類型節

napi_create_string_utf8#
napi_status napi_create_string_utf8(napi_env env,
                                    const char* str,
                                    size_t length,
                                    napi_value* result)
  • [in] env:API 呼叫所在的環境。
  • [in] str: 代表 UTF8 編碼字串的字元緩衝區。
  • [in] length: 字串長度(位元組),如果它是 null 結尾的字串,則為 NAPI_AUTO_LENGTH
  • [out] result: 代表 JavaScript stringnapi_value

如果 API 成功,則回傳 napi_ok

此 API 從 UTF8 編碼的 C 字串建立 JavaScript string 值。原生字串會被複製。

JavaScript string 類型描述於 ECMAScript 語言規範的 字串類型節

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

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

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

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

如果 API 成功,則回傳 napi_ok

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

JavaScript string 類型描述於 ECMAScript 語言規範的 字串類型節

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

如果 API 成功,則回傳 napi_ok

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

JavaScript string 類型描述於 ECMAScript 語言規範的 字串類型節

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

如果 API 成功,則回傳 napi_ok

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

JavaScript string 類型描述於 ECMAScript 語言規範的 字串類型節

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

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

如果 API 成功,則回傳 napi_ok

此 API 回傳陣列的長度。

Array 長度描述於 ECMAScript 語言規範的 Array 實例長度節

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

如果 API 成功,則回傳 napi_ok

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

警告: 使用此 API 時請謹慎。即使在回傳後,底層資料緩衝區的生命週期仍由 ArrayBufferSharedArrayBuffer 管理。一種可能安全使用此 API 的方法是結合 napi_create_reference 使用,這可用於保證對 ArrayBufferSharedArrayBuffer 生命週期的控制。只要沒有呼叫可能觸發 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 參數的值已經調整,以便 data 指向陣列中的第一個元素。因此,原生陣列的第一個位元組將位於 data - byte_offset

如果 API 成功,則回傳 napi_ok

此 API 回傳 TypedArray 的各種屬性。

如果不需要某個屬性,任何輸出參數都可以是 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: 作為 double 的時間值,表示自 1970 年 1 月 1 日午夜 UTC 以來的毫秒數。

此 API 不會考慮閏秒;它們會被忽略,因為 ECMAScript 與 POSIX 時間規範對齊。

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

此 API 回傳給定 JavaScript Date 的 C double 原始時間值。

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

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

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

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

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

此 API 回傳給定 JavaScript number 的 C double 原始等效值。

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

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

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

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

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

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

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

如果 API 成功,則回傳 napi_ok

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

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

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

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

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

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

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

如果該數字超過了 32 位元整數的範圍,則結果會被截斷為低 32 位元的等效值。如果值 > 231 - 1,這可能導致大的正數變成負數。

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

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

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

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

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

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

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

如果 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,則字串長度(位元組,不含 null 終結字元)將回傳在 result 中。
  • [in] bufsize: 目標緩衝區的大小。當此值不足時,回傳的字串會被截斷並以 null 結尾。如果此值為零,則不會回傳字串,也不會對緩衝區進行任何更改。
  • [out] result: 複製到緩衝區中的位元組數(不含 null 終結字元)。

如果 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,則字串長度(以雙位元組程式碼單元計算,不含 null 終結字元)將回傳。
  • [in] bufsize: 目標緩衝區的大小。當此值不足時,回傳的字串會被截斷並以 null 結尾。如果此值為零,則不會回傳字串,也不會對緩衝區進行任何更改。
  • [out] result: 複製到緩衝區中的雙位元組程式碼單元數(不含 null 終結字元)。

如果 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 不是 External 值,則回傳 napi_invalid_arg

此 API 代表類似於在物件上呼叫 typeof 運算子的行為,該運算子定義於 ECMAScript 語言規範的 typeof 運算子節。然而,有一些差異

  1. 它支援偵測 External 值。
  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 的布林值。

如果 API 成功,則回傳 napi_ok

此 API 代表在物件上呼叫 instanceof 運算子,該運算子定義於 ECMAScript 語言規範的 instanceof 運算子節

napi_is_array#

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

如果 API 成功,則回傳 napi_ok

此 API 代表在物件上呼叫 IsArray 運算,該運算定義於 ECMAScript 語言規範的 IsArray 節

napi_is_arraybuffer#

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

如果 API 成功,則回傳 napi_ok

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

napi_is_buffer#

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

如果 API 成功,則回傳 napi_ok

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

napi_is_date#

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

如果 API 成功,則回傳 napi_ok

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

napi_is_error#

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

如果 API 成功,則回傳 napi_ok

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

napi_is_typedarray#

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

如果 API 成功,則回傳 napi_ok

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

napi_is_dataview#

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

如果 API 成功,則回傳 napi_ok

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

napi_strict_equals#

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

如果 API 成功,則回傳 napi_ok

此 API 代表呼叫嚴格相等演算法,該演算法定義於 ECMAScript 語言規範的 IsStrctEqual 節

napi_detach_arraybuffer#

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

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

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

此 API 代表呼叫 ArrayBuffer 分離運算,該運算定義於 ECMAScript 語言規範的 detachArrayBuffer 節

napi_is_detached_arraybuffer#

napi_status napi_is_detached_arraybuffer(napi_env env,
                                         napi_value arraybuffer,
                                         bool* result)
  • [in] env:API 呼叫所在的環境。
  • [in] arraybuffer: 要檢查的 JavaScript ArrayBuffer
  • [out] result: arraybuffer 是否已被分離。

如果 API 成功,則回傳 napi_ok

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

此 API 代表呼叫 ArrayBuffer IsDetachedBuffer 運算,該運算定義於 ECMAScript 語言規範的 isDetachedBuffer 節

node_api_is_sharedarraybuffer#

穩定性:1 - 實驗性

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

如果 API 成功,則回傳 napi_ok

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

node_api_create_sharedarraybuffer#

穩定性:1 - 實驗性

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

如果 API 成功,則回傳 napi_ok

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

所分配的 SharedArrayBuffer 將具有底層位元組緩衝區,其大小由傳入的 byte_length 參數決定。底層緩衝區可選擇性地回傳給呼叫者,以供呼叫者直接操作該緩衝區。此緩衝區只能由原生程式碼直接寫入。若要從 JavaScript 寫入此緩衝區,需要建立 TypedArray 或 DataView 物件。

JavaScript SharedArrayBuffer 物件描述於 ECMAScript 語言規範的 SharedArrayBuffer 物件節

處理 JavaScript 屬性#

Node-API 暴露了一組 API 來獲取和設定 JavaScript 物件上的屬性。

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

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

Node-API 值由 napi_value 類型表示。任何需要 JavaScript 值的 Node-API 呼叫都會接收一個 napi_value。然而,呼叫者有責任確保所涉及的 napi_value 是 API 所預期的 JavaScript 類型。

本節記錄的 API 為在 napi_value 代表的任意 JavaScript 物件上獲取和設定屬性提供了簡單的介面。

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

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

使用 Node-API 值可以執行等效操作,使用以下程式碼片段

napi_status status = napi_generic_failure;

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

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

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

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

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

使用 Node-API 值可以執行等效操作,使用以下程式碼片段

napi_status status = napi_generic_failure;

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

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

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

屬性可以使用本節描述的 API 進行檢索。考慮以下 JavaScript 程式碼片段

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

以下大致等同於 Node-API 對應物

napi_status status = napi_generic_failure;

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

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

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

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

以下大致等同於 Node-API 對應物

napi_status status = napi_status_generic_failure;

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

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

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

結構#

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

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

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

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

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

  • napi_default:未在屬性上設定顯式屬性。預設情況下,屬性是唯讀的、不可枚舉且不可配置的。
  • napi_writable:屬性是可寫的。
  • napi_enumerable:屬性是可枚舉的。
  • napi_configurable:屬性是可配置的,定義於 ECMAScript 語言規範屬性屬性節
  • napi_static:該屬性將被定義為類別上的靜態屬性,而不是預設的實例屬性。這僅由 napi_define_class 使用。它會被 napi_define_properties 忽略。
  • napi_default_method:像 JS 類別中的方法一樣,該屬性是可配置且可寫的,但不可枚舉。
  • napi_default_jsproperty:像在 JavaScript 中透過賦值設定的屬性一樣,該屬性是可寫、可枚舉且可配置的。
napi_property_descriptor#
typedef struct {
  // One of utf8name or name should be NULL.
  const char* utf8name;
  napi_value name;

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

  napi_property_attributes attributes;
  void* data;
} napi_property_descriptor;
  • utf8name:描述該屬性鍵的可選字串,以 UTF8 編碼。必須提供 utf8namename 其中之一作為該屬性。
  • name:可選的 napi_value,指向要用作該屬性鍵的 JavaScript 字串或符號。必須提供 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: 代表 JavaScript 值陣列的 napi_value,這些值代表物件的屬性名稱。napi_get_array_lengthnapi_get_element 可用於迭代 result

如果 API 成功,則回傳 napi_ok

此 API 回傳一個包含此物件可用屬性名稱的陣列。

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

如果 API 成功,則回傳 napi_ok

此 API 設定傳入 Object 的屬性。

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

如果 API 成功,則回傳 napi_ok

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

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

如果 API 成功,則回傳 napi_ok

此 API 檢查傳入的 Object 是否具有該命名屬性。

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

如果 API 成功,則回傳 napi_ok

此 API 嘗試刪除 objectkey 自身屬性。

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

如果 API 成功,則回傳 napi_ok

此 API 檢查傳入的 Object 是否具有該命名自身屬性。key 必須是 stringsymbol,否則將會拋出錯誤。Node-API 不會執行資料類型之間的任何轉換。

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

如果 API 成功,則回傳 napi_ok

此方法等同於呼叫 napi_set_property,並傳入一個由 utf8Name 建立的 napi_value

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

如果 API 成功,則回傳 napi_ok

此方法等同於呼叫 napi_get_property,並傳入一個由 utf8Name 建立的 napi_value

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

如果 API 成功,則回傳 napi_ok

此方法等同於呼叫 napi_has_property,並傳入一個由 utf8Name 建立的 napi_value

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

如果 API 成功,則回傳 napi_ok

此 API 設定傳入 Object 的元素。

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

如果 API 成功,則回傳 napi_ok

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

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

如果 API 成功,則回傳 napi_ok

此 API 回傳傳入的 Object 在所請求索引處是否具有元素。

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

如果 API 成功,則回傳 napi_ok

此 API 嘗試刪除 object 的指定 index

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

如果 API 成功,則回傳 napi_ok

此方法允許在給定物件上有效率地定義多個屬性。屬性使用屬性描述符進行定義(參見 napi_property_descriptor)。給定此類屬性描述符的陣列,此 API 將根據 DefineOwnProperty()(描述於 ECMA-262 規範的 DefineOwnProperty 節)所定義的,逐一設定物件上的屬性。

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

如果 API 成功,則回傳 napi_ok

此方法凍結給定物件。這可以防止向其中新增新屬性、移除現有屬性、防止更改現有屬性的可枚舉性、可配置性或可寫性,並防止更改現有屬性的值。它還防止物件的原型被更改。這描述於 ECMA-262 規範的 第 19.1.2.6 節

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

如果 API 成功,則回傳 napi_ok

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

node_api_set_prototype#

穩定性:1 - 實驗性

napi_status node_api_set_prototype(napi_env env,
                                   napi_value object,
                                   napi_value value);
  • [in] env:呼叫 Node-API 時所在的環境。
  • [in] object: 要設定其原型的物件。
  • [in] value: 原型值。

如果 API 成功,則回傳 napi_ok

此 API 設定傳入 Object 的原型。

處理 JavaScript 函式#

Node-API 提供了一組允許 JavaScript 程式碼回呼至原生程式碼的 API。支援回呼至原生程式碼的 Node-API 會接收由 napi_callback 類型表示的回呼函式。當 JavaScript VM 回呼至原生程式碼時,會呼叫所提供的 napi_callback 函式。本節記錄的 API 允許回呼函式執行以下操作

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

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

任何透過 napi_property_descriptor 項目中的 data 欄位傳遞給此 API 的非 NULL 資料,都可以與 object 關聯,並透過將 object 與該資料一併傳遞給 napi_add_finalizer,以便在 object 被記憶體回收(garbage-collected)時進行釋放。

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] argv:代表作為函式引數傳入的 JavaScript 值的 napi_values 陣列。
  • [out] result:代表回傳的 JavaScript 物件的 napi_value

如果 API 成功,則回傳 napi_ok

此方法允許從原生插件(native add-on)呼叫 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-terminated),則設為 NAPI_AUTO_LENGTH
  • [in] cb:當此函式物件被呼叫時應執行原生函式。napi_callback 提供了更多詳細資訊。
  • [in] data:使用者提供的資料上下文。之後呼叫函式時,此資料會被傳回。
  • [out] result:代表新建立的 JavaScript 函式物件的 napi_value

如果 API 成功,則回傳 napi_ok

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

新建立的函式在此呼叫後不會自動在腳本中可見。相反地,必須在任何 JavaScript 可見的物件上明確設定一個屬性,才能讓該函式在腳本中被存取。

若要將函式公開為插件模組導出的一部分,請將新建立的函式設定在 exports 物件上。一個範例模組可能如下所示

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

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

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

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

  return exports;
}

NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)

根據上述程式碼,該插件可以在 JavaScript 中如下使用

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

傳遞給 require() 的字串是 binding.gyp 中負責建立 .node 檔案的目標名稱。

任何透過 data 參數傳遞給此 API 的非 NULL 資料,都可以與生成的 JavaScript 函式(透過 result 參數回傳)關聯,並透過將 JavaScript 函式與該資料一併傳遞給 napi_add_finalizer,以便在函式被記憶體回收時釋放。

JavaScript Function 在 ECMAScript 語言規範的 Function objects 章節中有描述。

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

物件封裝(Object wrap)#

Node-API 提供了一種「封裝(wrap)」C++ 類別和實例的方法,以便從 JavaScript 呼叫類別建構函式和方法。

  1. napi_define_class API 定義了一個 JavaScript 類別,包含與 C++ 類別相對應的建構函式、靜態屬性與方法,以及實例屬性與方法。
  2. 當 JavaScript 程式碼呼叫建構函式時,建構函式回呼會使用 napi_wrap 將新的 C++ 實例封裝在 JavaScript 物件中,然後回傳該封裝物件。
  3. 當 JavaScript 程式碼呼叫類別上的方法或屬性存取子(accessor)時,會呼叫對應的 napi_callback C++ 函式。對於實例回呼,napi_unwrap 會取得作為呼叫目標的 C++ 實例。

對於封裝的物件,區分「在類別原型(prototype)上呼叫的函式」與「在類別實例上呼叫的函式」可能會比較困難。解決此問題的一個常見模式是保存類別建構函式的持續性參照(persistent reference),以供稍後進行 instanceof 檢查。

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

當不再需要該參照時,必須將其釋放。

有時 napi_instanceof() 不足以確保 JavaScript 物件是特定原生型別的封裝。當封裝的 JavaScript 物件不是透過原型方法的 this 值,而是透過靜態方法傳回插件時,尤其會發生這種情況。在這種情況下,它們有可能被錯誤地解封(unwrapped)。

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() 是一個接受兩個引數的方法。第一個是資料庫控制代碼(handle),第二個是查詢控制代碼。在內部,它會解封第一個引數並將結果指標轉換為原生資料庫控制代碼。然後它會解封第二個引數並將結果指標轉換為查詢控制代碼。如果引數順序傳遞錯誤,型別轉換仍然會成功,但底層的資料庫操作很有可能會失敗,甚至導致無效的記憶體存取。

為了確保從第一個引數檢索到的指標確實是指向資料庫控制代碼的指標,且從第二個引數檢索到的指標確實是指向查詢控制代碼的指標,queryHasRecords() 的實作必須執行型別驗證。保留資料庫控制代碼實例化所使用的 JavaScript 類別建構函式,以及查詢控制代碼實例化所使用的建構函式在 napi_refs 中會有所幫助,因為隨後可以使用 napi_instanceof() 來確保傳入 queryHashRecords() 的實例確實是正確的型別。

不幸的是,napi_instanceof() 並不能防止原型篡改。例如,資料庫控制代碼實例的原型可以被設定為查詢控制代碼實例的建構函式原型。在這種情況下,資料庫控制代碼實例可能會被視為查詢控制代碼實例,並且它會通過查詢控制代碼實例的 napi_instanceof() 測試,儘管它仍然包含一個指向資料庫控制代碼的指標。

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

型別標記是一個對插件而言唯一的 128 位元整數。Node-API 提供了用於儲存型別標記的 napi_type_tag 結構。當該值與儲存在 napi_value 中的 JavaScript 物件或 external 一起傳遞給 napi_type_tag_object() 時,該 JavaScript 物件將會被「標記」。此「標記」在 JavaScript 端是不可見的。當 JavaScript 物件到達原生繫結時,可以使用 napi_check_object_type_tag() 搭配原始型別標記來判斷該 JavaScript 物件先前是否被該型別標記「標記」過。這創造了一種比 napi_instanceof() 更高精確度的型別檢查能力,因為這種型別標記在原型篡改以及插件卸載/重載後依然有效。

延續上述範例,以下骨架插件實作說明了 napi_type_tag_object()napi_check_object_type_tag() 的使用。

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

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

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

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

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

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

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

  return result;
}

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

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

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

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

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

napi_define_class#

napi_status napi_define_class(napi_env env,
                              const char* utf8name,
                              size_t length,
                              napi_callback constructor,
                              void* data,
                              size_t property_count,
                              const napi_property_descriptor* properties,
                              napi_value* result);
  • [in] env:API 呼叫所在的環境。
  • [in] utf8name:JavaScript 建構函式的名稱。為了清晰起見,建議在封裝 C++ 類別時使用 C++ 類別名稱。
  • [in] lengthutf8name 的位元組長度,若字串以空字元結尾(null-terminated),則設為 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++ 類別時,在透過 napi_unwrap 檢索放入 JavaScript 物件實例中的 C++ 類別實例後,可以從屬性描述符中給出的非 napi_static 屬性的靜態函式中呼叫 C++ 類別的非靜態資料屬性、存取子和方法。

當封裝 C++ 類別時,透過 constructor 傳遞的 C++ 建構函式回呼應該是類別上的一個靜態方法,它呼叫實際的類別建構函式,然後將新的 C++ 實例封裝在 JavaScript 物件中,並回傳封裝物件。詳情請參閱 napi_wrap

napi_define_class 回傳的 JavaScript 建構函式通常會被儲存起來,以便稍後從原生程式碼建構該類別的新實例,和/或檢查所提供的值是否為該類別的實例。在這種情況下,為防止函式值被記憶體回收,可以使用 napi_create_reference 為其建立強持續性參照,確保參照計數保持 >= 1。

任何透過 data 參數或 napi_property_descriptor 陣列項目的 data 欄位傳遞給此 API 的非 NULL 資料,都可以與生成的 JavaScript 建構函式(透過 result 參數回傳)關聯,並透過將 JavaScript 函式與該資料一併傳遞給 napi_add_finalizer,以便在類別被記憶體回收時釋放。

napi_wrap#

napi_status napi_wrap(napi_env env,
                      napi_value js_object,
                      void* native_object,
                      napi_finalize finalize_cb,
                      void* finalize_hint,
                      napi_ref* result);
  • [in] env:API 呼叫所在的環境。
  • [in] js_object:將作為原生物件封裝器的 JavaScript 物件。
  • [in] native_object:將被封裝在 JavaScript 物件中的原生實例。
  • [in] finalize_cb:選擇性的原生回呼,可用於在 JavaScript 物件被記憶體回收時釋放原生實例。napi_finalize 提供了更多詳細資訊。
  • [in] finalize_hint:傳遞給結束回呼(finalize callback)的選擇性上下文提示。
  • [out] result:封裝物件的選擇性參照。

如果 API 成功,則回傳 napi_ok

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

當 JavaScript 程式碼呼叫使用 napi_define_class() 定義的類別建構函式時,會呼叫該建構函式的 napi_callback。在建構原生類別的實例後,該回呼必須接著呼叫 napi_wrap(),將新建構的實例封裝在已經建立的 JavaScript 物件中(該物件即為建構函式回呼的 this 引數)。(該 this 物件是從建構函式的 prototype 建立的,因此它已經擁有了所有實例屬性和方法的定義。)

通常在封裝類別實例時,應該提供一個結束回呼,該回呼僅需刪除作為結束回呼 data 引數所接收的原生實例。

選擇性的回傳參照最初是一個弱參照(weak reference),這意味著它的參照計數為 0。通常此參照計數會在需要該實例保持有效的非同步操作期間暫時遞增。

注意:選擇性的回傳參照(若已取得)應僅在回應結束回呼呼叫時透過 napi_delete_reference 刪除。如果在此之前刪除它,那麼結束回呼可能永遠不會被呼叫。因此,在取得參照時,同時也需要結束回呼,以便正確處理參照的銷毀。

結束回呼可能會被延遲,這會留下一段時間視窗:物件已被記憶體回收(且弱參照無效),但結束回呼尚未被呼叫。當在 napi_wrap() 回傳的弱參照上使用 napi_get_reference_value() 時,您仍應處理空結果。

在同一個物件上第二次呼叫 napi_wrap() 將會回傳錯誤。若要將另一個原生實例與該物件關聯,請先使用 napi_remove_wrap()

napi_unwrap#

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

如果 API 成功,則回傳 napi_ok

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

當 JavaScript 程式碼呼叫類別上的方法或屬性存取子時,會呼叫對應的 napi_callback。如果該回呼是針對實例方法或存取子,則該回呼的 this 引數即為封裝物件;此時可以透過在封裝物件上呼叫 napi_unwrap() 來取得作為呼叫目標的 C++ 實例。

napi_remove_wrap#

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

如果 API 成功,則回傳 napi_ok

檢索先前使用 napi_wrap() 封裝在 JavaScript 物件 js_object 中的原生實例,並移除封裝。如果封裝有關聯的結束回呼,當 JavaScript 物件被記憶體回收時,該回呼將不再被呼叫。

napi_type_tag_object#

napi_status napi_type_tag_object(napi_env env,
                                 napi_value js_object,
                                 const napi_type_tag* type_tag);
  • [in] env:API 呼叫所在的環境。
  • [in] js_object:要被標記的 JavaScript 物件或 external
  • [in] type_tag:要標記該物件的標籤。

如果 API 成功,則回傳 napi_ok

type_tag 指標的值與 JavaScript 物件或 external 關聯。隨後可以使用 napi_check_object_type_tag() 來比較附加到該物件上的標籤與插件擁有的標籤,以確保物件具有正確的型別。

如果該物件已經有關聯的型別標籤,此 API 將回傳 napi_invalid_arg

napi_check_object_type_tag#

napi_status napi_check_object_type_tag(napi_env env,
                                       napi_value js_object,
                                       const napi_type_tag* type_tag,
                                       bool* result);
  • [in] env:API 呼叫所在的環境。
  • [in] js_object:要檢查其型別標籤的 JavaScript 物件或 external
  • [in] type_tag:用來與物件上找到的任何標籤進行比較的標籤。
  • [out] result:給定的型別標籤是否與物件上的型別標籤相符。如果在物件上未找到型別標籤,也會回傳 false

如果 API 成功,則回傳 napi_ok

將作為 type_tag 給定的指標與 js_object 上可以找到的任何指標進行比較。如果 js_object 上未找到標籤,或者雖然找到了標籤但與 type_tag 不符,則 result 被設為 false。如果找到了標籤且與 type_tag 相符,則 result 被設為 true

napi_add_finalizer#

napi_status napi_add_finalizer(napi_env env,
                               napi_value js_object,
                               void* finalize_data,
                               node_api_basic_finalize finalize_cb,
                               void* finalize_hint,
                               napi_ref* result);
  • [in] env:API 呼叫所在的環境。
  • [in] js_object:要附加原生資料的 JavaScript 物件。
  • [in] finalize_data:傳遞給 finalize_cb 的選擇性資料。
  • [in] finalize_cb:當 JavaScript 物件被記憶體回收時,將用於釋放原生資料的原生回呼。napi_finalize 提供了更多詳細資訊。
  • [in] finalize_hint:傳遞給結束回呼(finalize callback)的選擇性上下文提示。
  • [out] result:該 JavaScript 物件的選擇性參照。

如果 API 成功,則回傳 napi_ok

新增一個當 js_object 中的 JavaScript 物件被記憶體回收時會被呼叫的 napi_finalize 回呼。

此 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:傳遞給結束回呼(finalize callback)的選擇性上下文提示。

如果 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 參數將是插件提供的 void* 資料(即傳入 napi_create_async_work 呼叫的資料)。

建立完成後,非同步工作者可以使用 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 hooks
  • [in] async_resource_name:所提供資源型別的識別碼,用於 async_hooks API 公開的診斷資訊。
  • [in] execute:應被呼叫以非同步執行邏輯的原生函式。給定的函式從工作者執行緒池(worker pool thread)中呼叫,並且可以與主事件迴圈執行緒平行執行。
  • [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 應為空字元結尾的 UTF-8 編碼字串。

async_resource_name 識別碼由使用者提供,應能代表所執行的非同步工作型別。亦建議對識別碼套用命名空間,例如包含模組名稱。更多資訊請參閱 async_hooks 文件

napi_delete_async_work#

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

如果 API 成功,則回傳 napi_ok

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

即使有掛起的 JavaScript 例外狀況,也可以呼叫此 API。

napi_queue_async_work#

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

如果 API 成功,則回傳 napi_ok

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

napi_cancel_async_work#

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

如果 API 成功,則回傳 napi_ok

此 API 在排隊的工作尚未開始時取消該工作。如果它已經開始執行,則無法取消並將回傳 napi_generic_failure。如果成功,complete 回呼將以 napi_cancelled 的狀態值被呼叫。即使已成功取消,也不應在 complete 回呼呼叫之前刪除該工作。

即使有掛起的 JavaScript 例外狀況,也可以呼叫此 API。

自訂非同步操作#

上述簡單的非同步工作 API 可能不適用於所有場景。當使用任何其他非同步機制時,必須使用下列 API 以確保執行階段(runtime)正確追蹤非同步操作。

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 hooks,並可由 async_hooks.executionAsyncResource() 存取。
  • [in] async_resource_name:所提供資源型別的識別碼,用於 async_hooks API 公開的診斷資訊。
  • [out] result:初始化的非同步上下文。

如果 API 成功,則回傳 napi_ok

為了保留與先前版本的 ABI 相容性,為 async_resource 傳遞 NULL 不會導致錯誤。然而,這不建議使用,因為這會導致 async_hooks init hooksasync_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 不會導致錯誤。然而,這會導致非同步 hook 運作不正確。潛在問題包括在使用 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 在回呼期間安排在微任務佇列(microtask queue)上的任何 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 hooks。此參數已被棄用,執行階段會忽略它。請改用 napi_async_init 中的 async_resource 參數。
  • [in] context:正在呼叫該回呼的非同步操作的上下文。這應該是先前從 napi_async_init 取得的值。
  • [out] result:新建立的範圍(scope)。

在某些情況下(例如解析 promise),在進行某些 Node-API 呼叫時,必須擁有與回呼相關聯的等效範圍。如果堆疊上沒有其他腳本,則可以使用 napi_open_callback_scopenapi_close_callback_scope 函式來開啟/關閉所需的範圍。

napi_close_callback_scope#

NAPI_EXTERN napi_status napi_close_callback_scope(napi_env env,
                                                  napi_callback_scope scope)
  • [in] env:API 呼叫所在的環境。
  • [in] scope:要關閉的範圍。

即使有掛起的 JavaScript 例外狀況,也可以呼叫此 API。

版本管理#

napi_get_node_version#

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

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

如果 API 成功,則回傳 napi_ok

此函式會以目前執行中的 Node.js 主版本、次版本與修補版本填充 version 結構,並將 release 欄位設為 process.release.name 的值。

回傳的緩衝區是靜態分配的,無需釋放。

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 objects 章節所述。它將 promises 實作為一對物件。當由 napi_create_promise() 建立 promise 時,會建立一個「延遲(deferred)」物件並與 Promise 一起回傳。延遲物件與建立的 Promise 綁定,並且是使用 napi_resolve_deferred()napi_reject_deferred() 來 resolve 或 reject 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() 函式會執行其非同步操作,然後 resolve 或 reject 延遲物件,從而結束 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() 以分別 resolve 或 reject 相關聯的 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:要 resolve 其相關聯 promise 的延遲物件。
  • [in] resolution:用於 resolve promise 的值。

此 API 透過相關聯的延遲物件來 resolve 一個 JavaScript promise。因此,它只能用於 resolve 已取得對應延遲物件的 JavaScript promises。這實際上意味著 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:要 resolve 其相關聯 promise 的延遲物件。
  • [in] rejection:用於 reject promise 的值。

此 API 透過相關聯的延遲物件來 reject 一個 JavaScript promise。因此,它只能用於 reject 已取得對應延遲物件的 JavaScript promises。這實際上意味著 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 不同,此函式不允許腳本存取當前的語彙範圍(lexical scope),因此也不允許存取 模組範圍(module scope),這意味著諸如 require 之類的虛擬全域變數將無法使用。
  • 腳本可以存取 全域範圍(global scope)。腳本中的函式和 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 建立了一個持續性參照,該值持有一個可以從多個執行緒呼叫的 JavaScript 函式。呼叫是非同步發生的。這意味著要呼叫 JavaScript 回呼的值將被放入一個佇列中,並且對於佇列中的每個值,最終都會對 JavaScript 函式進行一次呼叫。

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

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

呼叫執行緒安全函式#

napi_call_threadsafe_function() 可用於發起對 JavaScript 的呼叫。napi_call_threadsafe_function() 接受一個控制 API 是否以阻塞方式運作的參數。如果設為 napi_tsfn_nonblocking,API 將以非阻塞方式運作,若佇列已滿則回傳 napi_queue_full,防止資料成功加入佇列。如果設為 napi_tsfn_blocking,API 將阻塞直到佇列中有空間可用。如果執行緒安全函式建立時的最大佇列大小為 0,則 napi_call_threadsafe_function() 永遠不會阻塞。

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

實際呼叫 JavaScript 的過程由透過 call_js_cb 參數給定的回呼所控制。對於透過 napi_call_threadsafe_function() 的成功呼叫而放入佇列中的每個值,call_js_cb 都會在主執行緒上被呼叫一次。如果未給定此類回呼,則將使用預設回呼,且產生的 JavaScript 呼叫將沒有引數。call_js_cb 回呼在其參數中接收要呼叫的 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_finalize 回呼(即傳遞給 napi_create_threadsafe_function() 的回呼)中釋放。napi_create_threadsafe_functioninitial_thread_count 參數標記了執行緒安全函式的初始獲取數量,而不是在建立時多次呼叫 napi_acquire_threadsafe_function

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

執行緒安全函式可以透過將 napi_tsfn_abort 的值提供給 napi_release_threadsafe_function() 來「中止」。這將導致所有與該執行緒安全函式相關的後續 API(除了 napi_release_threadsafe_function() 外)回傳 napi_closing,即使在參照計數達到零之前也是如此。特別是,napi_call_threadsafe_function() 將回傳 napi_closing,從而通知各執行緒對執行緒安全函式的非同步呼叫已不再可能。這可以用作終止執行緒的準則。當從 napi_call_threadsafe_function() 接收到 napi_closing 的回傳值時,執行緒不得再使用該執行緒安全函式,因為它已不再保證被分配。

決定是否保持進程運作#

與 libuv 控制代碼類似,執行緒安全函式可以被「參照(referenced)」和「取消參照(unreferenced)」。一個「參照的」執行緒安全函式會導致建立它的執行緒上的事件迴圈保持活著,直到該執行緒安全函式被銷毀為止。相反地,一個「未參照的」執行緒安全函式不會阻止事件迴圈退出。API napi_ref_threadsafe_functionnapi_unref_threadsafe_function 正是用於此目的。

napi_unref_threadsafe_function 不會將執行緒安全函式標記為可銷毀,napi_ref_threadsafe_function 也不能防止它被銷毀。

napi_create_threadsafe_function#

NAPI_EXTERN napi_status
napi_create_threadsafe_function(napi_env env,
                                napi_value func,
                                napi_value async_resource,
                                napi_value async_resource_name,
                                size_t max_queue_size,
                                size_t initial_thread_count,
                                void* thread_finalize_data,
                                napi_finalize thread_finalize_cb,
                                void* context,
                                napi_threadsafe_function_call_js call_js_cb,
                                napi_threadsafe_function* result);
  • [in] env:API 呼叫所在的環境。
  • [in] func:一個選擇性的 JavaScript 函式,用於從另一個執行緒呼叫。如果將 NULL 傳遞給 call_js_cb,則必須提供此參數。
  • [in] async_resource:一個與非同步工作關聯的可選物件,該物件將被傳遞給可能的 async_hooks init hooks
  • [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 值為 undefinednapi_threadsafe_function_call_js 提供了更多詳細資訊。
  • [out] result:非同步執行緒安全 JavaScript 函式。

變更歷史

  • 版本 10 (NAPI_VERSION 定義為 10 或更高)

    call_js_cb 中拋出的未捕捉異常會透過 'uncaughtException' 事件進行處理,而不是被忽略。

napi_get_threadsafe_function_context#

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

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

napi_call_threadsafe_function#

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

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

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

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

napi_acquire_threadsafe_function#

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

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

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

napi_release_threadsafe_function#

NAPI_EXTERN napi_status
napi_release_threadsafe_function(napi_threadsafe_function func,
                                 napi_threadsafe_function_release_mode mode);
  • [in] func:要遞減其參照計數的非同步執行緒安全 JavaScript 函式。
  • [in] mode:旗標,其值可以是 napi_tsfn_release(指示當前執行緒不會再呼叫該執行緒安全函式),或 napi_tsfn_abort(指示除了當前執行緒外,沒有其他執行緒應再呼叫該執行緒安全函式)。如果設為 napi_tsfn_abort,對 napi_call_threadsafe_function() 的進一步呼叫將回傳 napi_closing,且不再有值被放入佇列。

執行緒在停止使用 func 時應呼叫此 API。在呼叫此 API 後將 func 傳遞給任何執行緒安全 API 的結果是未定義的,因為 func 可能已經被銷毀。

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

napi_ref_threadsafe_function#

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

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

napi_unref_threadsafe_function 不會將執行緒安全函式標記為可銷毀,napi_ref_threadsafe_function 也不能防止它被銷毀。napi_acquire_threadsafe_functionnapi_release_threadsafe_function 是為此目的而提供的。

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

napi_unref_threadsafe_function#

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

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

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

雜項工具#

node_api_get_module_file_name#

NAPI_EXTERN napi_status
node_api_get_module_file_name(node_api_basic_env env, const char** result);

  • [in] env:API 呼叫所在的環境。
  • [out] result:一個包含載入插件之位置絕對路徑的 URL。對於本地檔案系統上的檔案,它將以 file:// 開頭。該字串以空字元結尾,由 env 擁有,因此不得修改或釋放。

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