Перейти к содержанию

Node-API

v18.x.x

Стабильность: 2 – Стабильная

АПИ является удовлетворительным. Совместимость с NPM имеет высший приоритет и не будет нарушена кроме случаев явной необходимости.

Node-API (ранее N-API) - это API для создания собственных аддонов. Он не зависит от базовой среды выполнения JavaScript (например, V8) и поддерживается как часть самого Node.js. Этот API будет стабильным Application Binary Interface (ABI) во всех версиях Node.js. Он предназначен для того, чтобы изолировать аддоны от изменений в основном движке JavaScript и позволить модулям, скомпилированным для одной основной версии, работать на более поздних основных версиях Node.js без перекомпиляции. Руководство ABI Stability содержит более подробное объяснение.

Аддоны собираются/пакуются с использованием того же подхода/инструментов, которые описаны в разделе C++ Addons. Единственное различие заключается в наборе API, которые используются родным кодом. Вместо использования API V8 или Native Abstractions for Node.js, используются функции, доступные в Node-API.

API, предоставляемые Node-API, обычно используются для создания и манипулирования значениями JavaScript. Концепции и операции в целом соответствуют идеям, указанным в спецификации языка ECMA-262. API обладают следующими свойствами:

  • Все вызовы Node-API возвращают код состояния типа napi_status. Этот статус указывает, был ли вызов API успешным или неудачным.
  • Возвращаемое значение API передается через параметр out.
  • Все значения JavaScript абстрагируются за непрозрачным типом с именем napi_value.
  • В случае кода состояния ошибки, дополнительную информацию можно получить с помощью napi_get_last_error_info. Более подробную информацию можно найти в разделе обработки ошибок Error handling.

Node-API - это C API, который обеспечивает стабильность ABI в версиях Node.js и на разных уровнях компиляторов. API на C++ может быть проще в использовании. Для поддержки использования C++ в проекте поддерживается модуль-обертка C++ под названием node-addon-api. Эта обертка предоставляет API C++ с возможностью инлайнинга. Двоичные файлы, собранные с node-addon-api, будут зависеть от символов для функций Node-API на C, экспортируемых Node.js. node-addon-api - это более эффективный способ написания кода, вызывающего Node-API. Возьмем, к примеру, следующий код node-addon-api. В первой части показан код node-addon-api, а во второй - то, что на самом деле используется в аддоне.

1
2
Object obj = Object::New(env);
obj["foo"] = String::New(env, "bar");
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
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. В результате он все еще получает преимущества стабильности ABI, обеспечиваемой C API.

При использовании node-addon-api вместо C API, начните с API docs для node-addon-api.

Ресурс Node-API Resource предлагает отличную ориентацию и советы для разработчиков, только начинающих работать с Node-API и node-addon-api. Дополнительные медиа-ресурсы можно найти на странице Node-API Media.

Последствия стабильности ABI

Хотя Node-API обеспечивает гарантию стабильности ABI, другие части Node.js этого не делают, и любые внешние библиотеки, используемые из аддона, могут этого не делать. В частности, ни один из следующих API не обеспечивает гарантию стабильности ABI в основных версиях:

  • API Node.js C++, доступные через любой из следующих интерфейсов

    1
    2
    3
    4
    #include <node.h>
    #include <node_buffer.h>
    #include <node_version.h>
    #include <node_object_wrap.h>
    
  • API libuv, которые также включены в Node.js и доступны через

    1
    #include <uv.h>
    
  • API V8, доступный через

    1
    #include <v8.h>
    

Таким образом, чтобы аддон оставался ABI-совместимым во всех основных версиях Node.js, он должен использовать исключительно Node-API, ограничивая себя использованием

1
#include <node_api.h>

и проверяя для всех внешних библиотек, которые она использует, что внешняя библиотека дает гарантии стабильности ABI, аналогичные Node-API.

Построение

В отличие от модулей, написанных на JavaScript, разработка и развертывание нативных аддонов Node.js с использованием Node-API требует дополнительного набора инструментов. Помимо основных инструментов, необходимых для разработки под Node.js, разработчику нативных аддонов требуется инструментарий, способный компилировать код на C и C++ в двоичный файл. Кроме того, в зависимости от способа развертывания нативного аддона, пользователь нативного аддона также должен иметь установленную инструментальную цепочку C/C++.

Для разработчиков Linux, необходимые пакеты инструментария C/C++ легко доступны. GCC широко используется в сообществе Node.js для сборки и тестирования на различных платформах. Для многих разработчиков инфраструктура компилятора LLVM также является хорошим выбором.

Для Mac-разработчиков Xcode предлагает все необходимые инструменты компилятора. Однако нет необходимости устанавливать всю IDE Xcode. Следующая команда устанавливает необходимый набор инструментов:

1
xcode-select --install

Для разработчиков Windows Visual Studio предлагает все необходимые инструменты компилятора. Однако нет необходимости устанавливать всю Visual Studio IDE. Следующая команда устанавливает необходимый набор инструментов:

1
npm install --global windows-build-tools

В следующих разделах описаны дополнительные инструменты, доступные для разработки и развертывания нативных аддонов Node.js.

Инструменты сборки

Оба перечисленных здесь инструмента требуют, чтобы у пользователей нативного аддона был установлен инструментарий C/C++ для успешной установки нативного аддона.

node-gyp

node-gyp - это система сборки, основанная на форке gyp-next инструмента Google GYP и поставляемая в комплекте с npm. GYP, и, следовательно, node-gyp, требует, чтобы был установлен Python.

Исторически node-gyp был самым популярным инструментом для создания нативных аддонов. Он имеет широкое распространение и документацию. Однако некоторые разработчики столкнулись с ограничениями node-gyp.

CMake.js

CMake.js - это альтернативная система сборки, основанная на CMake.

CMake.js является хорошим выбором для проектов, которые уже используют CMake или для разработчиков, пострадавших от ограничений в node-gyp.

Загрузка предварительно скомпилированных двоичных файлов

Три перечисленных здесь инструмента позволяют разработчикам и сопровождающим нативных аддонов создавать и загружать двоичные файлы на публичные или частные серверы. Эти инструменты обычно интегрируются с системами сборки CI/CD, такими как Travis CI и AppVeyor для создания и загрузки двоичных файлов для различных платформ и архитектур. Эти двоичные файлы затем доступны для загрузки пользователям, которым не нужно иметь установленный инструментарий 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 - хороший выбор для проектов GitHub, использующих CMake.js.

prebuildify

prebuildify - это инструмент, основанный на node-gyp. Преимущество prebuildify в том, что собранные двоичные файлы идут в комплекте с родным аддоном, когда он загружается на npm. Двоичные файлы загружаются из npm и сразу же становятся доступны пользователю модуля при установке родного аддона.

Использование

Чтобы использовать функции Node-API, включите файл node_api.h, который находится в каталоге src в дереве разработки node:

1
#include <node_api.h>

В результате будет выбрана NAPI_VERSION по умолчанию для данного выпуска Node.js. Для обеспечения совместимости с конкретными версиями Node-API, версия может быть указана явно при включении заголовка:

1
2
#define NAPI_VERSION 3
#include <node_api.h>

Это ограничивает поверхность Node-API только той функциональностью, которая была доступна в указанных (и более ранних) версиях.

Некоторые возможности Node-API являются экспериментальными и требуют явного согласия:

1
2
#define NAPI_EXPERIMENTAL
#include <node_api.h>

В этом случае вся поверхность API, включая любые экспериментальные API, будет доступна коду модуля.

Матрица версий Node-API

Версии Node-API аддитивны и версионируются независимо от Node.js. Версия 4 является расширением версии 3 в том смысле, что она имеет все API из версии 3 с некоторыми дополнениями. Это означает, что нет необходимости в перекомпиляции для новых версий Node.js, которые указаны как поддерживающие более позднюю версию.

1 2 3
v6.x v6.14.2\*
v8.x v8.6.0\*\* v8.10.0\* v8.11.2
v9.x v9.0.0\* v9.3.0\* v9.11.0\*
≥ v10.x все релизы все релизы все релизы
4 5 6 7 8
v10.x v10.16.0 v10.17.0 v10.20.0 v10.23.0
v11.x v11.8.0
v12.x v12.0.0 v12.11.0 v12.17.0 v12.19.0 v12.22.0
v13.x v13.0.0 v13.0.0
v14.x v14.0.0 v14.0.0 v14.0.0 v14.12.0 v14.17.0
v15.x v15.0.0 v15.0.0 v15.0.0 v15.0.0 v15.12.0
v16.x v16.0.0 v16.0.0 v16.0.0 v16.0.0 v16.0.0

* Node-API был экспериментальным.

** Node.js 8.0.0 включал Node-API как экспериментальный. Он был выпущен как Node-API версии 1, но продолжал развиваться до Node.js 8.6.0. API отличается в версиях до Node.js 8.6.0. Мы рекомендуем Node-API версии 3 или более поздней.

Каждый API, документированный для Node-API, будет иметь заголовок добавлено в:, а API, которые являются стабильными, будут иметь дополнительный заголовок Node-API version:. API можно непосредственно использовать при использовании версии Node.js, которая поддерживает версию Node-API, указанную в Node-API version: или выше. При использовании версии Node.js, которая не поддерживает указанную в Node-API version: или если не указана Node-API version:, то API будет доступен только в том случае, если #define NAPI_EXPERIMENTAL предшествует включению опции

Node-интерфейсы, связанные исключительно с доступом к функциям ECMAScript из нативного кода, можно найти отдельно в js_native_api.h и js_native_api_types.h. API, определенные в этих заголовках, включены в node_api.h и node_api_types.h. Заголовки структурированы таким образом, чтобы позволить реализацию Node-API за пределами Node.js. Для таких реализаций API, специфичные для Node.js, могут быть неприменимы.

Части аддона, специфичные для Node.js, могут быть отделены от кода, который раскрывает фактическую функциональность для среды JavaScript, так что последний может быть использован с несколькими реализациями Node-API. В примере ниже addon.c и addon.h ссылаются только на js_native_api.h. Это гарантирует, что addon.c может быть повторно использован для компиляции как с Node.js реализацией Node-API, так и с любой реализацией Node-API вне Node.js.

addon_node.c - это отдельный файл, который содержит специфическую для Node.js точку входа в аддон и который инстанцирует аддон, вызывая addon.c, когда аддон загружается в среду Node.js.

1
2
3
4
5
6
// addon.h
#ifndef _ADDON_H_
#define _ADDON_H_
#include <js_native_api.h>
napi_value create_addon(napi_env env);
#endif  // _ADDON_H_
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// addon.c
#include "addon.h"

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

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

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

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

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

  return result;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// addon_node.c
#include <node_api.h>
#include "addon.h"

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

API жизненного цикла среды

Раздел 8.7 Спецификации языка ECMAScript определяет понятие "Агент" как самодостаточную среду, в которой выполняется код JavaScript. Несколько таких Агентов могут быть запущены и завершены одновременно или последовательно процессом.

Среда Node.js соответствует Агенту ECMAScript. В основном процессе среда создается при запуске, а дополнительные среды могут быть созданы в отдельных потоках, чтобы служить в качестве рабочих потоков. Когда Node.js встроен в другое приложение, основной поток приложения также может создавать и уничтожать окружение Node.js несколько раз в течение жизненного цикла процесса приложения, так что каждое окружение Node.js, созданное приложением, может, в свою очередь, в течение своего жизненного цикла создавать и уничтожать дополнительные окружения в качестве рабочих потоков.

С точки зрения нативного аддона это означает, что предоставляемые им привязки могут быть вызваны несколько раз, из нескольких контекстов и даже одновременно из нескольких потоков.

Нативным аддонам может понадобиться распределить глобальное состояние, которое они используют во время жизненного цикла среды Node.js так, чтобы состояние было уникальным для каждого экземпляра аддона.

Для этого Node-API предоставляет способ связать данные таким образом, чтобы их жизненный цикл был связан с жизненным циклом среды Node.js.

napi_set_instance_data.

1
2
3
4
napi_status napi_set_instance_data(napi_env env,
                                   void* data,
                                   napi_finalize finalize_cb,
                                   void* finalize_hint);
  • [in] env: Среда, в которой вызывается вызов Node-API.
  • [in] data: Элемент данных, который должен быть доступен для привязок этого экземпляра.
  • [in] finalize_cb: Функция, вызываемая при завершении работы среды. Функция получает данные, чтобы освободить их. napi_finalize предоставляет более подробную информацию.
  • [in] finalize_hint: Необязательная подсказка для передачи обратному вызову finalize во время сбора.

Возвращает napi_ok, если API завершился успешно.

Этот API связывает data с текущим окружением Node.js. Позже данные могут быть получены с помощью napi_get_instance_data(). Любые существующие данные, связанные с текущим окружением Node.js, которые были установлены с помощью предыдущего вызова napi_set_instance_data(), будут перезаписаны. Если предыдущим вызовом был предоставлен finalize_cb, он не будет вызван.

napi_get_instance_data

1
2
napi_status napi_get_instance_data(napi_env env,
                                   void** data);
  • [in] env: Среда, в которой вызывается вызов Node-API.
  • [out] data: Элемент данных, который был ранее связан с текущим запущенным окружением Node.js вызовом napi_set_instance_data().

Возвращает napi_ok, если API завершился успешно.

Этот API извлекает данные, которые были ранее связаны с текущим запущенным окружением Node.js посредством napi_set_instance_data(). Если данные не были установлены, вызов будет успешным, а data будет установлена в NULL.

Основные типы данных Node-API

Node-API предоставляет следующие основные типы данных в качестве абстракций, которые используются различными API. Эти API должны рассматриваться как непрозрачные, доступные только с помощью других вызовов Node-API.

napi_status

Интегральный код состояния, указывающий на успех или неудачу вызова Node-API. В настоящее время поддерживаются следующие коды состояния.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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_status;

Если требуется дополнительная информация о том, что API вернул статус отказа, ее можно получить, вызвав napi_get_last_error_info.

napi_extended_error_info

1
2
3
4
5
6
typedef struct {
  const char* error_message;
  void* engine_reserved;
  uint32_t engine_error_code;
  napi_status error_code;
} napi_extended_error_info;
  • error_message: Строка в кодировке UTF8, содержащая VM-нейтральное описание ошибки.
  • engine_reserved: Зарезервировано для деталей ошибки, специфичных для ВМ. В настоящее время это не реализовано ни для одной ВМ.
  • engine_error_code: Код ошибки, специфичный для ВМ. В настоящее время это не реализовано ни для одной ВМ.
  • error_code: Код состояния Node-API, который возник при последней ошибке.

Дополнительную информацию смотрите в разделе Обработка ошибок.

napi_env.

napi_env используется для представления контекста, который базовая реализация Node-API может использовать для сохранения специфического состояния VM. Эта структура передается родным функциям, когда они вызываются, и должна быть передана обратно при выполнении вызовов Node-API. В частности, тот же napi_env, который был передан при вызове начальной нативной функции, должен быть передан всем последующим вложенным вызовам Node-API. Кэширование napi_env с целью общего повторного использования, а также передача napi_env между экземплярами одного и того же аддона, запущенными на разных потоках Worker, не допускается. Значение napi_env становится недействительным, когда экземпляр нативного аддона выгружается. Уведомление об этом событии передается через обратные вызовы, заданные в napi_add_env_cleanup_hook и napi_set_instance_data.

napi_value.

Это непрозрачный указатель, который используется для представления значения JavaScript.

napi_threadsafe_function

Это непрозрачный указатель, представляющий функцию JavaScript, которая может быть вызвана асинхронно из нескольких потоков через napi_call_threadsafe_function().

napi_threadsafe_function_release_mode

Значение, передаваемое napi_release_threadsafe_function() для указания того, должна ли потокобезопасная функция быть немедленно закрыта (napi_tsfn_abort) или просто освобождена (napi_tsfn_release) и таким образом доступна для последующего использования через napi_acquire_threadsafe_function() и napi_call_threadsafe_function().

1
2
3
4
typedef enum {
  napi_tsfn_release,
  napi_tsfn_abort
} napi_threadsafe_function_release_mode;

napi_threadsafe_function_call_mode

Значение, передаваемое napi_call_threadsafe_function() для указания того, должен ли вызов блокироваться всякий раз, когда очередь, связанная с потокобезопасной функцией, заполнена.

1
2
3
4
typedef enum {
  napi_tsfn_nonblocking,
  napi_tsfn_blocking
} napi_threadsafe_function_call_mode;

Типы управления памятью Node-API

napi_handle_scope.

Это абстракция, используемая для управления и изменения времени жизни объектов, созданных в определенной области видимости. В общем случае, значения Node-API создаются в контексте области видимости handle. Когда родной метод вызывается из JavaScript, по умолчанию будет существовать область видимости handle. Если пользователь явно не создаст новую область видимости, значения Node-API будут созданы в области видимости по умолчанию. Для любых вызовов кода вне выполнения родного метода (например, во время вызова обратного вызова libuv), модуль должен создать область видимости перед вызовом любых функций, которые могут привести к созданию значений JavaScript.

Области действия создаются с помощью napi_open_handle_scope и уничтожаются с помощью napi_close_handle_scope. Закрытие области видимости может указать GC, что все napi_value, созданные во время жизни области видимости хэндла, больше не являются ссылками из текущего кадра стека.

Более подробную информацию можно найти в разделе Управление временем жизни объектов.

napi_escapable_handle_scope.

Escapable handle scopes - это специальный тип handle scope для возврата значений, созданных в конкретной handle scope, в родительскую область.

napi_ref

Это абстракция, используемая для ссылки на napi_value. Это позволяет пользователям управлять временем жизни значений JavaScript, включая явное определение их минимального времени жизни.

Для получения более подробной информации ознакомьтесь с Управление временем жизни объектов.

napi_type_tag.

128-битное значение, хранящееся в виде двух беззнаковых 64-битных целых чисел. Служит в качестве UUID, которым можно "пометить" объекты JavaScript, чтобы убедиться, что они относятся к определенному типу. Это более надежная проверка, чем napi_instanceof, поскольку последняя может выдать ложное срабатывание, если прототип объекта был изменен. Тегирование типов наиболее полезно в сочетании с napi_wrap, поскольку оно гарантирует, что указатель, полученный из обернутого объекта, может быть безопасно приведен к собственному типу, соответствующему тегу типа, который был ранее применен к объекту JavaScript.

1
2
3
4
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.

Тип указателя функции для собственных функций, предоставляемых пользователем, которые должны быть открыты для JavaScript через Node-API. Функции обратного вызова должны удовлетворять следующей сигнатуре:

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

Если только по причинам, обсуждаемым в Object Lifetime Management, создание хэндла и/или области обратного вызова внутри napi_callback не является необходимым.

napi_finalize.

Тип указателя функции для функций, предоставляемых дополнениями, которые позволяют пользователю получать уведомления, когда данные, принадлежащие внешним пользователям, готовы к очистке, поскольку объект, с которым они были связаны, был очищен от мусора. Пользователь должен предоставить функцию, удовлетворяющую следующей сигнатуре, которая будет вызываться после сбора объекта. В настоящее время, napi_finalize может быть использована для выяснения того, когда объекты, имеющие внешние данные, будут собраны.

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

Если только по причинам, обсуждаемым в Object Lifetime Management, создание хэндла и/или области обратного вызова внутри тела функции не является необходимым.

napi_async_execute_callback.

Указатель функции, используемый с функциями, поддерживающими асинхронные операции. Функции обратного вызова должны удовлетворять следующей сигнатуре:

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

Реализация этой функции должна избегать вызовов Node-API, которые выполняют JavaScript или взаимодействуют с объектами JavaScript. Вызовы Node-API должны быть в napi_async_complete_callback вместо этого. Не используйте параметр napi_env, так как это может привести к выполнению JavaScript.

napi_async_complete_callback.

Указатель функции, используемый с функциями, поддерживающими асинхронные операции. Функции обратного вызова должны удовлетворять следующей сигнатуре:

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

Если только по причинам, обсуждаемым в Object Lifetime Management, создание хэндла и/или области обратного вызова внутри тела функции не является необходимым.

napi_threadsafe_function_call_js.

Указатель функции, используемый при асинхронных потокобезопасных вызовах функций. Обратный вызов будет вызван в основном потоке. Его цель - использовать элемент данных, поступающий через очередь из одного из вторичных потоков, для построения параметров, необходимых для вызова JavaScript, обычно через napi_call_function, и затем выполнить вызов JavaScript.

Данные, поступающие из вторичного потока через очередь, указываются в параметре data, а функция JavaScript для вызова - в параметре js_callback.

Node-API устанавливает среду до вызова этого обратного вызова, поэтому достаточно вызвать функцию JavaScript через napi_call_function, а не через napi_make_callback.

Функции обратного вызова должны удовлетворять следующей сигнатуре:

1
2
3
4
typedef void (*napi_threadsafe_function_call_js)(napi_env env,
                                                 napi_value js_callback,
                                                 void* context,
                                                 void* data);
  • [in] env: Окружение, используемое для вызовов API, или NULL, если потокобезопасная функция завершается и данные могут быть освобождены.
  • [in] js_callback: Функция JavaScript для вызова, или NULL, если потокобезопасная функция завершается и data может потребоваться освободить. Это также может быть NULL, если потокобезопасная функция была создана без js_callback.
  • [в] контексте: Необязательные данные, с которыми была создана потокобезопасная функция.
  • [in] data: Данные, созданные вторичным потоком. В обязанности обратного вызова входит преобразование этих собственных данных в значения JavaScript (с помощью функций Node-API), которые могут быть переданы в качестве параметров при вызове js_callback. Этот указатель полностью управляется потоками и этим обратным вызовом. Таким образом, этот обратный вызов должен освободить данные.

Если только по причинам, обсуждаемым в Object Lifetime Management, создание хэндла и/или области видимости обратного вызова внутри тела функции не является необходимым.

napi_cleanup_hook.

Указатель функции, используемый с napi_add_env_cleanup_hook. Он будет вызван, когда среда будет снесена.

Функции обратного вызова должны удовлетворять следующей сигнатуре:

1
typedef void (*napi_cleanup_hook)(void* data);

napi_async_cleanup_hook.

Указатель функции, используемый с napi_add_async_cleanup_hook. Она будет вызвана, когда среда будет снесена.

Функции обратного вызова должны удовлетворять следующей сигнатуре:

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

Тело функции должно инициировать асинхронные действия по очистке, в конце которых handle должен быть передан в вызов napi_remove_async_cleanup_hook.

Обработка ошибок

Node-API использует как возвращаемые значения, так и исключения JavaScript для обработки ошибок. В следующих разделах объясняется подход для каждого случая.

Возвращаемые значения

Все функции Node-API имеют один и тот же шаблон обработки ошибок. Тип возврата всех функций API - napi_status.

Возвращаемое значение будет napi_ok, если запрос был успешным и не было брошено ни одного не пойманного исключения JavaScript. Если произошла ошибка И было выброшено исключение, будет возвращено значение napi_status для ошибки. Если исключение было выброшено, но ошибка не произошла, будет возвращено значение napi_pending_exception.

В случаях, когда возвращается значение, отличное от napi_ok или napi_pending_exception, необходимо вызвать napi_is_exception_pending, чтобы проверить, ожидает ли исключение. Более подробную информацию см. в разделе об исключениях.

Полный набор возможных значений napi_status определен в napi_api_types.h.

Возвращаемое значение napi_status представляет собой независимое от виртуальной машины представление произошедшей ошибки. В некоторых случаях полезно иметь возможность получить более подробную информацию, включая строку, представляющую ошибку, а также информацию, специфичную для VM (движка).

Для получения такой информации предусмотрена функция napi_get_last_error_info, которая возвращает структуру napi_extended_error_info. Формат структуры napi_extended_error_info следующий:

1
2
3
4
5
6
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: Код ошибки, специфичный для ВМ.
  • error_code: Код состояния Node-API для последней ошибки.

napi_get_last_error_info возвращает информацию о последнем совершенном вызове Node-API.

Не полагайтесь на содержание или формат любой из расширенной информации, поскольку она не является предметом SemVer и может измениться в любое время. Она предназначена только для целей протоколирования.

napi_get_last_error_info.

1
2
3
napi_status
napi_get_last_error_info(napi_env env,
                         const napi_extended_error_info** result);
  • [in] env: Среда, в которой вызывается API.
  • [out] result: Структура napi_extended_error_info с дополнительной информацией об ошибке.

Возвращает napi_ok, если API прошел успешно.

Этот API извлекает структуру napi_extended_error_info с информацией о последней произошедшей ошибке.

Содержимое возвращаемой структуры napi_extended_error_info действительно только до вызова функции Node-API на том же env. Это включает вызов napi_is_exception_pending, поэтому часто может потребоваться сделать копию информации, чтобы ее можно было использовать позже. Указатель, возвращаемый в error_message, указывает на статически определенную строку, поэтому безопасно использовать этот указатель, если вы скопировали его из поля error_message (которое будет перезаписано) до вызова другой функции Node-API.

Не полагайтесь на содержание или формат любой из расширенной информации, поскольку она не является предметом SemVer и может измениться в любое время. Она предназначена только для целей протоколирования.

Этот API может быть вызван, даже если существует ожидающее исключение JavaScript.

Исключения

Любой вызов функции Node-API может привести к исключению JavaScript. Это касается любой из функций API, даже тех, которые могут не вызывать выполнение JavaScript.

Если napi_status, возвращаемый функцией, равен napi_ok, то исключение не ожидается и никаких дополнительных действий не требуется. Если возвращаемый napi_status не равен napi_ok или napi_pending_exception, то для того, чтобы попытаться восстановиться и продолжить работу, а не просто немедленно вернуться, необходимо вызвать napi_is_exception_pending, чтобы определить, ожидается ли исключение или нет.

Во многих случаях, когда вызывается функция Node-API и исключение уже ожидает своего завершения, функция немедленно возвращается со napi_status в napi_pending_exception. Однако это не относится ко всем функциям. Node-API позволяет вызывать подмножество функций, чтобы обеспечить минимальную очистку перед возвратом к JavaScript. В этом случае napi_status будет отражать статус для функции. Он не будет отражать предыдущие ожидающие исключения. Чтобы избежать путаницы, проверяйте статус ошибки после каждого вызова функции.

Когда исключение находится в состоянии ожидания, можно применить один из двух подходов.

Первый подход заключается в том, чтобы выполнить любую соответствующую очистку, а затем вернуться, чтобы выполнение вернулось к JavaScript. Как часть перехода обратно к JavaScript, исключение будет выброшено в той точке кода JavaScript, где был вызван родной метод. Поведение большинства вызовов Node-API не определено, пока исключение находится в ожидании, и многие просто возвращают napi_pending_exception, поэтому делайте как можно меньше, а затем возвращайтесь в JavaScript, где исключение может быть обработано.

Второй подход - попытаться обработать исключение. Бывают случаи, когда родной код может поймать исключение, предпринять соответствующие действия, а затем продолжить работу. Это рекомендуется делать только в особых случаях

Следующие полезные функции также доступны на случай, если родному коду понадобится бросить исключение или определить, является ли napi_value экземпляром объекта JavaScript Error: napi_throw_error, napi_throw_type_error, napi_throw_range_error, node_api_throw_syntax_error и napi_is_error.

Также доступны следующие служебные функции на случай, если нативному коду понадобится создать объект Error: napi_create_error, napi_create_type_error, napi_create_range_error и node_api_create_syntax_error, где result - это napi_value, которое ссылается на вновь созданный объект JavaScript Error.

Проект Node.js добавляет коды ошибок ко всем ошибкам, генерируемым внутри проекта. Цель состоит в том, чтобы приложения использовали эти коды ошибок для проверки всех ошибок. Соответствующие сообщения об ошибках останутся, но будут использоваться только для регистрации и отображения с расчетом на то, что сообщение может измениться без применения SemVer. Для поддержки этой модели в Node-API, как во внутренней функциональности, так и для функциональности, специфичной для модуля (в соответствии с хорошей практикой), функции throw_ и create_ принимают необязательный параметр code, который является строкой для кода, добавляемого к объекту ошибки. Если необязательный параметр равен NULL, то код не будет связан с ошибкой. Если код указан, имя, связанное с ошибкой, также будет обновлено:

1
originalName [code]

где originalName - оригинальное имя, связанное с ошибкой, а code - код, который был предоставлен. Например, если код 'ERR_ERROR_1' и создается TypeError, то имя будет таким:

1
TypeError [ERR_ERROR_1]

napi_throw.

1
NAPI_EXTERN napi_status napi_throw(napi_env env, napi_value error);
  • [in] env: Среда, в которой вызывается API.
  • [in] error: Значение JavaScript, которое будет выброшено.

Возвращает napi_ok, если API прошел успешно.

Этот API выбрасывает предоставленное значение JavaScript.

napi_throw_error.

1
2
3
NAPI_EXTERN napi_status napi_throw_error(napi_env env,
                                         const char* code,
                                         const char* msg);
  • [in] env: Среда, в которой вызывается API.
  • [in] code: Необязательный код ошибки, который будет установлен в случае ошибки.
  • [in] msg: Строка C, представляющая текст, который будет связан с ошибкой.

Возвращает napi_ok, если API прошел успешно.

Этот API выбрасывает JavaScript Error с указанным текстом.

napi_throw_type_error.

1
2
3
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, представляющая текст, который будет связан с ошибкой.

Возвращает napi_ok, если API прошел успешно.

Этот API выбрасывает JavaScript TypeError с указанным текстом.

napi_throw_range_error.

1
2
3
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, представляющая текст, который будет связан с ошибкой.

Возвращает napi_ok, если API прошел успешно.

Этот API выбрасывает JavaScript RangeError с указанным текстом.

node_api_throw_syntax_error.

Стабильность: 1 – Экспериментальная

Фича изменяется и не допускается флагом командной строки. Может быть изменена или удалена в последующих версиях.

1
2
3
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, представляющая текст, который будет связан с ошибкой.

Возвращает napi_ok, если API прошел успешно.

Этот API выбрасывает JavaScript SyntaxError с предоставленным текстом.

napi_is_error.

1
2
3
NAPI_EXTERN napi_status napi_is_error(napi_env env,
                                      napi_value value,
                                      bool* result);
  • [in] env: Среда, в которой вызывается API.
  • [in] value: Проверяемое napi_value.
  • [out] result: Булево значение, которое устанавливается в true, если napi_value представляет ошибку, и false в противном случае.

Возвращает napi_ok, если API прошел успешно.

Этот API запрашивает napi_value, чтобы проверить, представляет ли оно объект ошибки.

napi_create_error.

1
2
3
4
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: napi_value, ссылающееся на JavaScript строку, которая будет использоваться в качестве сообщения для ошибки.
  • [out] result: napi_value, представляющее созданную ошибку.

Возвращает napi_ok, если API завершился успешно.

Этот API возвращает JavaScript Error с предоставленным текстом.

napi_create_type_error.

1
2
3
4
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: napi_value, ссылающееся на JavaScript строку, которая будет использоваться в качестве сообщения для ошибки.
  • [out] result: napi_value, представляющее созданную ошибку.

Возвращает napi_ok, если API завершился успешно.

Этот API возвращает JavaScript TypeError с предоставленным текстом.

napi_create_range_error.

1
2
3
4
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: napi_value, ссылающееся на JavaScript строку, которая будет использоваться в качестве сообщения для ошибки.
  • [out] result: napi_value, представляющее созданную ошибку.

Возвращает napi_ok, если API завершился успешно.

Этот API возвращает JavaScript RangeError с предоставленным текстом.

node_api_create_syntax_error.

Стабильность: 1 – Экспериментальная

Фича изменяется и не допускается флагом командной строки. Может быть изменена или удалена в последующих версиях.

1
2
3
4
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: napi_value, ссылающееся на JavaScript строку, которая будет использоваться в качестве сообщения для ошибки.
  • [out] result: napi_value, представляющее созданную ошибку.

Возвращает napi_ok, если API завершился успешно.

Этот API возвращает JavaScript SyntaxError с предоставленным текстом.

napi_get_and_clear_last_exception.

1
2
napi_status napi_get_and_clear_last_exception(napi_env env,
                                              napi_value* result);
  • [in] env: Среда, в которой вызывается API.
  • [out] result: Исключение, если оно ожидается, NULL в противном случае.

Возвращает napi_ok, если API завершился успешно.

Этот API может быть вызван, даже если есть ожидающее исключение JavaScript.

napi_is_exception_pending.

1
napi_status napi_is_exception_pending(napi_env env, bool* result);
  • [in] env: Среда, в которой вызывается API.
  • [out] result: Булево значение, которое устанавливается в true, если ожидается исключение.

Возвращает napi_ok, если API завершился успешно.

Этот API может быть вызван, даже если есть ожидающее исключение JavaScript.

napi_fatal_exception.

1
napi_status napi_fatal_exception(napi_env env, napi_value err);
  • [in] env: Среда, в которой вызывается API.
  • [in] err: Ошибка, которая передается в 'uncaughtException'.

Вызвать 'uncaughtException' в JavaScript. Полезно, если асинхронный обратный вызов выбрасывает исключение без возможности восстановления.

Фатальные ошибки

В случае возникновения неустранимой ошибки в родном аддоне, можно вызвать фатальную ошибку, чтобы немедленно завершить процесс.

napi_fatal_error.

1
2
3
4
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: Длина местоположения в байтах, или NAPI_AUTO_LENGTH, если оно нуль-концевое.
  • [in] message: Сообщение, связанное с ошибкой.
  • [in] message_len: Длина сообщения в байтах, или NAPI_AUTO_LENGTH, если оно нуль-концевое.

Вызов функции не возвращается, процесс будет завершен.

Этот API может быть вызван даже при наличии ожидающего исключения JavaScript.

Управление временем жизни объекта

При вызове Node-API в качестве napi_values могут быть возвращены дескрипторы объектов в куче для базовой виртуальной машины. Эти дескрипторы должны удерживать объекты "живыми" до тех пор, пока они не перестанут требоваться исходному коду, иначе объекты могут быть собраны до того, как исходный код закончит их использовать.

По мере возврата обработчиков объектов они ассоциируются с "областью видимости". Время жизни области видимости по умолчанию привязано к времени жизни вызова родного метода. В результате по умолчанию хэндлы остаются действительными, а объекты, связанные с этими хэндлами, будут существовать в течение всего срока действия вызова родного метода.

Во многих случаях, однако, необходимо, чтобы дескрипторы оставались действительными в течение более короткого или более длительного времени, чем время жизни родного метода. В следующих разделах описаны функции Node-API, которые могут быть использованы для изменения времени жизни хэндлов по сравнению со значением по умолчанию.

Сделать срок жизни хэндла короче, чем у родного метода

Часто бывает необходимо сделать время жизни хэндлов короче, чем время жизни родного метода. Например, рассмотрим собственный метод, в котором есть цикл, выполняющий итерации по элементам большого массива:

1
2
3
4
5
6
7
8
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_scope и napi_close_handle_scope.

Node-API поддерживает только одну вложенную иерархию диапазонов. В любой момент времени существует только одна активная область видимости, и все новые ручки будут связаны с этой областью видимости, пока она активна. Закрытие диапазонов должно происходить в порядке, обратном их открытию. Кроме того, все области видимости, созданные в родном методе, должны быть закрыты до возврата из этого метода.

Если взять предыдущий пример, то добавление вызовов napi_open_handle_scope и napi_close_handle_scope гарантирует, что в течение всего цикла будет действовать только один хэндл:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
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_scope и napi_close_escapable_handle_scope.

Запрос на продвижение хэндла осуществляется через napi_escape_handle, который может быть вызван только один раз.

napi_open_handle_scope.

1
2
NAPI_EXTERN napi_status napi_open_handle_scope(napi_env env,
                                               napi_handle_scope* result);
  • [in] env: Среда, в которой вызывается API.
  • [out] result: napi_value, представляющее новую область видимости.

Возвращает napi_ok, если API завершился успешно.

Этот API открывает новую область видимости.

napi_close_handle_scope.

1
2
NAPI_EXTERN napi_status napi_close_handle_scope(napi_env env,
                                                napi_handle_scope scope);
  • [in] env: Среда, в которой вызывается API.
  • [in] scope: napi_value, представляющее область видимости, которая должна быть закрыта.

Возвращает napi_ok, если API завершился успешно.

Этот API закрывает переданную область видимости. Сферы должны быть закрыты в порядке, обратном тому, в котором они были созданы.

Этот API может быть вызван, даже если существует ожидающее исключение JavaScript.

napi_open_escapable_handle_scope.

1
2
3
NAPI_EXTERN napi_status
    napi_open_escapable_handle_scope(napi_env env,
                                     napi_handle_scope* result);
  • [in] env: Среда, в которой вызывается API.
  • [out] result: napi_value, представляющее новую область видимости.

Возвращает napi_ok, если API завершился успешно.

Этот API открывает новую область видимости, из которой один объект может быть перемещен во внешнюю область видимости.

napi_close_escapable_handle_scope.

1
2
3
NAPI_EXTERN napi_status
    napi_close_escapable_handle_scope(napi_env env,
                                      napi_handle_scope scope);
  • [in] env: Среда, в которой вызывается API.
  • [in] scope: napi_value, представляющее область видимости, которая должна быть закрыта.

Возвращает napi_ok, если API завершился успешно.

Этот API закрывает переданную область видимости. Сферы должны быть закрыты в порядке, обратном тому, в котором они были созданы.

Этот API может быть вызван, даже если существует ожидающее исключение JavaScript.

napi_escape_handle.

1
2
3
4
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: napi_value, представляющее JavaScript Object, который должен быть экранирован.
  • [out] result: napi_value, представляющее handle к экранированному объекту во внешней области видимости.

Возвращает napi_ok, если API завершился успешно.

Этот API передает хэндл к объекту JavaScript так, чтобы он был действителен в течение всего времени существования внешней области видимости. Он может быть вызван только один раз для каждой области видимости. Если он будет вызван более одного раза, будет возвращена ошибка.

Этот API может быть вызван, даже если существует ожидающее исключение JavaScript.

Ссылки на объекты со сроком жизни, превышающим срок жизни родного метода.

В некоторых случаях аддону необходимо иметь возможность создавать и ссылаться на объекты со временем жизни, превышающим время жизни одного вызова собственного метода. Например, для создания конструктора и последующего использования этого конструктора в запросе на создание экземпляров, необходимо иметь возможность ссылаться на объект конструктора во многих различных запросах на создание экземпляров. Это невозможно с обычным дескриптором, возвращаемым как napi_value, как описано в предыдущем разделе. Время жизни обычного дескриптора управляется диапазонами, и все диапазоны должны быть закрыты до окончания работы родного метода.

Node-API предоставляет методы для создания постоянных ссылок на объект. Каждая постоянная ссылка имеет связанный с ней счетчик со значением 0 или выше. Счетчик определяет, будет ли ссылка поддерживать соответствующий объект в живом состоянии. Ссылки со значением count, равным 0, не препятствуют сбору объекта и часто называются "слабыми" ссылками. Любой счетчик больше 0 будет препятствовать сбору объекта.

Ссылки могут быть созданы с начальным количеством ссылок. Затем счетчик может быть изменен с помощью функций napi_reference_ref и napi_reference_unref. Если объект собран, когда счетчик ссылок равен 0, все последующие вызовы для получения объекта, связанного со ссылкой napi_get_reference_value вернут NULL для возвращаемого napi_value. Попытка вызвать napi_reference_ref для ссылки, объект которой был собран, приводит к ошибке.

Ссылки должны быть удалены, если они больше не нужны аддону. Когда ссылка удалена, она больше не будет препятствовать сбору соответствующего объекта. Если не удалить постоянную ссылку, произойдет "утечка памяти", при этом как собственная память для постоянной ссылки, так и соответствующий объект на куче будут сохранены навсегда.

Может быть создано несколько постоянных ссылок, ссылающихся на один и тот же объект, каждая из которых будет либо сохранять, либо не сохранять объект, основываясь на своем индивидуальном подсчете. Множество постоянных ссылок на один и тот же объект может привести к неожиданному оживлению родной памяти. Родные структуры для постоянной ссылки должны быть живыми u

napi_create_reference.

1
2
3
4
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, указывающий на новую ссылку.

Возвращает napi_ok, если API завершился успешно.

Этот API создает новую ссылку с указанным количеством ссылок на переданный Объект.

napi_delete_reference.

1
NAPI_EXTERN napi_status napi_delete_reference(napi_env env, napi_ref ref);
  • [in] env: Среда, в которой вызывается API.
  • [in] ref: napi_ref, который будет удален.

Возвращает napi_ok, если API прошел успешно.

Этот API удаляет переданную ссылку.

Этот API может быть вызван, даже если есть ожидающее исключение JavaScript.

napi_reference_ref.

1
2
3
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: Новое количество ссылок.

Возвращает napi_ok, если API завершился успешно.

Этот API увеличивает счетчик ссылок для переданной ссылки и возвращает результирующий счетчик ссылок.

napi_reference_unref.

1
2
3
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: Новое количество ссылок.

Возвращает napi_ok, если API завершился успешно.

Этот API уменьшает счетчик ссылок для переданной ссылки и возвращает результирующий счетчик ссылок.

napi_get_reference_value.

1
2
3
NAPI_EXTERN napi_status napi_get_reference_value(napi_env env,
                                                 napi_ref ref,
                                                 napi_value* result);

napi_value, передаваемое в или из этих методов, является дескриптором объекта, с которым связана ссылка.

  • [in] env: Среда, в которой вызывается API.
  • [in] ref: napi_ref, для которого мы запрашиваем соответствующий Object.
  • [out] result: napi_значение для объекта, на который ссылается napi_ref.

Возвращает napi_ok, если API завершился успешно.

В случае успеха API возвращает napi_value, представляющее JavaScript Object, связанный с napi_ref. В противном случае результатом будет NULL.

Очистка при выходе из текущего окружения Node.js

Хотя процесс Node.js обычно освобождает все свои ресурсы при выходе, встраивание Node.js или будущая поддержка Worker может потребовать от аддонов регистрации крючков очистки, которые будут выполняться при выходе из текущего окружения Node.js.

Node-API предоставляет функции для регистрации и снятия с регистрации таких обратных вызовов. Когда эти обратные вызовы выполняются, все ресурсы, которые удерживаются аддоном, должны быть освобождены.

napi_add_env_cleanup_hook.

1
2
3
NODE_EXTERN napi_status napi_add_env_cleanup_hook(napi_env env,
                                                  napi_cleanup_hook fun,
                                                  void* arg);

Регистрирует fun как функцию, которая будет запущена с параметром arg после выхода из текущей среды Node.js.

Функция может быть безопасно указана несколько раз с разными значениями arg. В этом случае она также будет вызываться несколько раз. Предоставление одинаковых значений fun и arg несколько раз не допускается и приведет к прерыванию процесса.

Хуки будут вызываться в обратном порядке, т.е. первым будет вызван самый последний добавленный хук.

Удалить этот хук можно с помощью napi_remove_env_cleanup_hook. Обычно это происходит, когда ресурс, для которого был добавлен этот хук, в любом случае будет снесен.

Для асинхронной очистки доступен napi_add_async_cleanup_hook.

napi_remove_env_cleanup_hook.

1
2
3
NAPI_EXTERN napi_status napi_remove_env_cleanup_hook(napi_env env,
                                                     void (*fun)(void* arg),
                                                     void* arg);

Снимает с регистрации fun как функцию, которая будет запущена с параметром arg после выхода из текущей среды Node.js. И аргумент, и значение функции должны быть точными.

Функция должна быть первоначально зарегистрирована с помощью napi_add_env_cleanup_hook, иначе процесс прервется.

napi_add_async_cleanup_hook.

1
2
3
4
5
NAPI_EXTERN napi_status napi_add_async_cleanup_hook(
    napi_env env,
    napi_async_cleanup_hook hook,
    void* arg,
    napi_async_cleanup_hook_handle* remove_handle);
  • [in] env: Среда, в которой вызывается API.
  • [in] hook: Указатель функции для вызова при разрушении среды.
  • [in] arg: Указатель для передачи в hook при вызове.
  • [out] remove_handle: Необязательный хэндл, ссылающийся на асинхронный хук очистки.

Регистрирует hook, который является функцией типа napi_async_cleanup_hook, как функцию, которая будет запущена с параметрами remove_handle и arg после выхода из текущего окружения Node.js.

В отличие от napi_add_env_cleanup_hook, хук может быть асинхронным.

В противном случае поведение в целом соответствует поведению napi_add_env_cleanup_hook.

Если remove_handle не является NULL, в нем будет сохранено непрозрачное значение, которое впоследствии должно быть передано в napi_remove_async_cleanup_hook, независимо от того, был ли хук уже вызван. Обычно это происходит, когда ресурс, для которого был добавлен этот хук, в любом случае будет снесен.

napi_remove_async_cleanup_hook.

1
2
NAPI_EXTERN napi_status napi_remove_async_cleanup_hook(
    napi_async_cleanup_hook_handle remove_handle);
  • [in] remove_handle: Хендл асинхронного крючка очистки, который был создан с помощью napi_add_async_cleanup_hook.

Снимает с регистрации хук очистки, соответствующий remove_handle. Это предотвратит выполнение хука, если только он уже не начал выполняться. Это должно быть вызвано для любого значения napi_async_cleanup_hook_handle, полученного из napi_add_async_cleanup_hook.

Финализация при выходе из среды Node.js

Среда Node.js может быть завершена в произвольный момент времени, как только это станет возможным, с запретом выполнения JavaScript, например, по запросу worker.terminate(). Когда среда завершается, зарегистрированные обратные вызовы napi_finalize для объектов JavaScript, Thread-safe функций и данных экземпляра среды вызываются немедленно и независимо.

Вызов обратных вызовов napi_finalize запланирован после зарегистрированных вручную хуков очистки. Чтобы обеспечить правильный порядок завершения работы аддона во время выключения окружения и избежать использования after-free в обратном вызове napi_finalize, аддоны должны зарегистрировать крючок очистки с napi_add_env_cleanup_hook и napi_add_async_cleanup_hook, чтобы вручную освободить выделенный ресурс в правильном порядке.

Регистрация модулей

Модули Node-API регистрируются аналогично другим модулям, за исключением того, что вместо макроса NODE_MODULE используется следующий:

1
NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)

Следующее отличие - сигнатура для метода Init. Для модуля Node-API она выглядит следующим образом:

1
napi_value Init(napi_env env, napi_value exports);

Возвращаемое значение из Init рассматривается как объект exports для модуля. Для удобства методу Init передается пустой объект через параметр exports. Если Init возвращает NULL, то параметр, переданный в качестве exports, экспортируется модулем. Модули Node-API не могут изменять объект module, но могут указать что угодно в качестве свойства exports модуля.

Добавить метод hello в качестве функции, чтобы его можно было вызывать как метод, предоставляемый аддоном:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
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() для аддона:

1
2
3
4
5
6
7
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):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
NAPI_MODULE_INIT() {
  napi_value answer;
  napi_status result;

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

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

  return exports;
}

Все аддоны Node-API являются контекстно-зависимыми, то есть они могут загружаться несколько раз. При объявлении такого модуля есть несколько конструктивных соображений. В документации по context-aware addons содержится больше подробностей.

Переменные env и exports будут доступны в теле функции после вызова макроса.

Подробнее о задании свойств объектам смотрите в разделе Работа со свойствами JavaScript.

Для получения более подробной информации о создании модулей аддонов в целом, обратитесь к существующему API.

Работа со значениями JavaScript

Node-API предоставляет набор API для создания всех типов значений JavaScript. Некоторые из этих типов документированы в Разделе 6 Спецификации языка ECMAScript.

В основном, эти API используются для выполнения одного из следующих действий:

  1. Создать новый объект JavaScript
  2. Преобразование из примитивного типа C в значение Node-API.
  3. Преобразование значения Node-API в примитивный тип C
  4. Получение глобальных экземпляров, включая undefined и null.

Значения Node-API представлены типом napi_value. Любой вызов Node-API, требующий значения JavaScript, принимает napi_value. В некоторых случаях API проверяет тип napi_value заранее. Однако для повышения производительности вызывающему лучше убедиться, что napi_value имеет тип JavaScript, ожидаемый API.

Типы перечислений

napi_key_collection_mode

1
2
3
4
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.

1
2
3
4
5
6
7
8
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.

1
2
3
4
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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
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. Как правило, он соответствует типам, описанным в разделе 6.1 спецификации языка ECMAScript. Помимо типов из этого раздела, napi_valuetype может также представлять функции и объекты с внешними данными.

JavaScript-значение типа napi_external отображается в JavaScript как обычный объект, у которого не может быть задано ни свойств, ни прототипа.

napi_typedarray_type.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
typedef enum {
  napi_int8_array,
  napi_uint8_array,
  napi_uint8_clamped_array,
  napi_int16_array,
  napi_uint16_array,
  napi_int32_array,
  napi_uint32_array,
  napi_float32_array,
  napi_float64_array,
  napi_bigint64_array,
  napi_biguint64_array,
} napi_typedarray_type;

Представляет собой бинарный скалярный тип данных, лежащий в основе TypedArray. Элементы этого перечисления соответствуют Разделу 22.2 Спецификации языка ECMAScript.

Функции создания объектов

napi_create_array.

1
napi_status napi_create_array(napi_env env, napi_value* result)
  • [in] env: Среда, в которой вызывается вызов Node-API.
  • [out] result: Значение napi_value, представляющее JavaScript Array.

Возвращает napi_ok, если API прошел успешно.

Этот API возвращает значение Node-API, соответствующее типу JavaScript Array. Массивы JavaScript описаны в Раздел 22.1 спецификации языка ECMAScript.

napi_create_array_with_length.

1
2
3
napi_status napi_create_array_with_length(napi_env env,
                                          size_t length,
                                          napi_value* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] length: Начальная длина массива.
  • [out] result: napi_value, представляющий JavaScript массив.

Возвращает napi_ok, если API завершился успешно.

Этот API возвращает значение Node-API, соответствующее типу JavaScript Array. Свойство длины Array устанавливается в переданный параметр длины. Однако не гарантируется, что буфер, лежащий в основе массива, будет предварительно выделен виртуальной машиной при его создании. Это поведение остается на усмотрение базовой реализации VM. Если буфер должен быть непрерывным блоком памяти, который может быть непосредственно прочитан и/или записан через C, используйте napi_create_external_arraybuffer.

Массивы JavaScript описаны в Разделе 22.1 спецификации языка ECMAScript.

napi_create_arraybuffer.

1
2
3
4
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: napi_value, представляющее JavaScript ArrayBuffer.

Возвращает napi_ok, если API прошел успешно.

Этот API возвращает значение Node-API, соответствующее JavaScript ArrayBuffer. Буферы ArrayBuffer используются для представления буферов двоичных данных фиксированной длины. Обычно они используются в качестве буфера-подложки для объектов TypedArray. Выделенный ArrayBuffer будет иметь базовый байтовый буфер, размер которого определяется переданным параметром length. Базовый буфер по желанию возвращается обратно вызывающей стороне в случае, если вызывающая сторона захочет напрямую работать с буфером. В этот буфер можно записывать только непосредственно из родного кода. Для записи в этот буфер из JavaScript необходимо создать типизированный массив или объект DataView.

Объекты JavaScript ArrayBuffer описаны в Раздел 24.1 спецификации языка ECMAScript.

napi_create_buffer.

1
2
3
4
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: napi_value, представляющее node::Buffer.

Возвращает napi_ok, если API завершился успешно.

Этот API выделяет объект node::Buffer. Хотя это все еще полностью поддерживаемая структура данных, в большинстве случаев достаточно использовать TypedArray.

napi_create_buffer_copy.

1
2
3
4
5
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: Указатель на базовый буфер данных нового буфера. При желании result_data можно игнорировать, передав NULL.
  • [out] result: napi_value, представляющее node::Buffer.

Возвращает napi_ok, если API завершился успешно.

Этот API выделяет объект node::Buffer и инициализирует его данными, скопированными из переданного буфера. Хотя это все еще полностью поддерживаемая структура данных, в большинстве случаев достаточно использовать TypedArray.

napi_create_date.

1
2
3
napi_status napi_create_date(napi_env env,
                             double time,
                             napi_value* result);
  • [in] env: Среда, в которой вызывается API.
  • [in] time: Значение времени ECMAScript в миллисекундах с 01 января 1970 года по UTC.
  • [out] result: napi_value, представляющее JavaScript Date.

Возвращает napi_ok, если API завершился успешно.

Этот API не учитывает високосные секунды; они игнорируются, поскольку ECMAScript соответствует спецификации времени POSIX.

Этот API выделяет объект JavaScript Date.

Объекты JavaScript Date описаны в Раздел 20.3 спецификации языка ECMAScript.

napi_create_external.

1
2
3
4
5
napi_status napi_create_external(napi_env env,
                                 void* data,
                                 napi_finalize finalize_cb,
                                 void* finalize_hint,
                                 napi_value* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] data: Необработанный указатель на внешние данные.
  • [in] finalize_cb: Необязательный обратный вызов для вызова, когда внешнее значение собирается. napi_finalize предоставляет более подробную информацию.
  • [in] finalize_hint: Необязательная подсказка для передачи обратному вызову finalize во время сбора.
  • [out] result: napi_value, представляющее внешнее значение.

Возвращает napi_ok, если API завершился успешно.

Этот API выделяет значение JavaScript с прикрепленными к нему внешними данными. Это используется для передачи внешних данных через код JavaScript, чтобы позже они могли быть получены родным кодом с помощью napi_get_value_external.

API добавляет обратный вызов napi_finalize, который будет вызван, когда только что созданный объект JavaScript будет собран.

Созданное значение не является объектом, и поэтому не поддерживает дополнительные свойства. Оно рассматривается как отдельный тип значения: вызов napi_typeof() с внешним значением дает napi_external.

napi_create_external_arraybuffer.

1
2
3
4
5
6
7
napi_status
napi_create_external_arraybuffer(napi_env env,
                                 void* external_data,
                                 size_t byte_length,
                                 napi_finalize finalize_cb,
                                 void* finalize_hint,
                                 napi_value* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] external_data: Указатель на базовый байтовый буфер ArrayBuffer.
  • [in] byte_length: Длина в байтах базового буфера.
  • [in] finalize_cb: Необязательный обратный вызов для вызова, когда ArrayBuffer собирается. napi_finalize предоставляет более подробную информацию.
  • [in] finalize_hint: Необязательная подсказка для передачи обратному вызову finalize во время сбора.
  • [out] result: napi_value, представляющее JavaScript ArrayBuffer.

Возвращает napi_ok, если API прошел успешно.

Некоторые среды выполнения, отличные от Node.js, отказались от поддержки внешних буферов. В других средах выполнения, кроме Node.js, этот метод может возвращать napi_no_external_buffers_allowed, чтобы указать, что внешние буферы не поддерживаются. Одним из таких режимов выполнения является Electron, описанный в этом выпуске electron/issues/35801.

Для поддержания широкой совместимости со всеми средами выполнения вы можете определить NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED в вашем аддоне перед включением заголовков node-api. Это позволит скрыть 2 функции, создающие внешние буферы. Это обеспечит возникновение ошибки компиляции, если вы случайно используете один из этих методов.

Этот API возвращает значение Node-API, соответствующее JavaScript ArrayBuffer. Байтовый буфер, лежащий в основе ArrayBuffer, выделяется и управляется извне. Вызывающая сторона должна убедиться, что байтовый буфер остается действительным до вызова обратного вызова finalize.

API добавляет обратный вызов napi_finalize, который будет вызван, когда только что созданный объект JavaScript будет собран.

JavaScript ArrayBuffer описан в Раздел 24.1 спецификации языка ECMAScript.

napi_create_external_buffer.

1
2
3
4
5
6
napi_status napi_create_external_buffer(napi_env env,
                                        size_t length,
                                        void* data,
                                        napi_finalize finalize_cb,
                                        void* finalize_hint,
                                        napi_value* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] length: Размер в байтах входного буфера (должен быть равен размеру нового буфера).
  • [in] data: Необработанный указатель на базовый буфер для передачи JavaScript.
  • [in] finalize_cb: Необязательный обратный вызов для вызова, когда ArrayBuffer собирается. napi_finalize предоставляет более подробную информацию.
  • [in] finalize_hint: Необязательная подсказка для передачи обратному вызову finalize во время сбора.
  • [out] result: napi_value, представляющее node::Buffer.

Возвращает napi_ok, если API прошел успешно.

Некоторые среды выполнения, отличные от Node.js, отказались от поддержки внешних буферов. В других средах выполнения, кроме Node.js, этот метод может возвращать napi_no_external_buffers_allowed, чтобы указать, что внешние буферы не поддерживаются. Одним из таких режимов выполнения является Electron, описанный в этом выпуске electron/issues/35801.

Для поддержания широкой совместимости со всеми средами выполнения вы можете определить NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED в вашем аддоне перед включением заголовков node-api. Это позволит скрыть 2 функции, создающие внешние буферы. Это обеспечит ошибку компиляции, если вы случайно используете один из этих методов.

Этот API выделяет объект node::Buffer и инициализирует его данными, подкрепленными переданным буфером. Хотя это все еще полностью поддерживаемая структура данных, в большинстве случаев достаточно использовать TypedArray.

API добавляет обратный вызов napi_finalize, который будет вызван, когда только что созданный объект JavaScript будет собран.

Для Node.js >=4 Буферы являются Uint8Array.

napi_create_object.

1
napi_status napi_create_object(napi_env env, napi_value* result)
  • [in] env: Среда, в которой вызывается API.
  • [out] result: Значение napi_value, представляющее JavaScript Object.

Возвращает napi_ok, если API завершился успешно.

Этот API выделяет JavaScript Object по умолчанию. Это эквивалентно выполнению new Object() в JavaScript.

Тип JavaScript Object описан в Раздел 6.1.7 спецификации языка ECMAScript.

napi_create_symbol.

1
2
3
napi_status napi_create_symbol(napi_env env,
                               napi_value description,
                               napi_value* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] description: Необязательное napi_value, ссылающееся на JavaScript строку, которая будет установлена в качестве описания для символа.
  • [out] result: Значение napi_value, представляющее JavaScript символ.

Возвращает napi_ok, если API завершился успешно.

Этот API создает значение JavaScript symbol из строки C в кодировке UTF8.

Тип JavaScript symbol описан в Раздел 19.4 спецификации языка ECMAScript.

node_api_symbol_for.

Стабильность: 1 – Экспериментальная

Фича изменяется и не допускается флагом командной строки. Может быть изменена или удалена в последующих версиях.

1
2
3
4
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: Длина строки описания в байтах, или NAPI_AUTO_LENGTH, если она является нуль-терминированной.
  • [out] result: Значение napi_value, представляющее JavaScript symbol.

Возвращает napi_ok, если API завершился успешно.

Этот API ищет в глобальном реестре существующий символ с заданным описанием. Если такой символ уже существует, он будет возвращен, в противном случае в реестре будет создан новый символ.

Тип JavaScript symbol описан в Раздел 19.4 спецификации языка ECMAScript.

napi_create_typedarray.

1
2
3
4
5
6
napi_status napi_create_typedarray(napi_env env,
                                   napi_typedarray_type type,
                                   size_t length,
                                   napi_value arraybuffer,
                                   size_t byte_offset,
                                   napi_value* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] type: Скалярный тип данных элементов в TypedArray.
  • [in] length: Количество элементов в TypedArray.
  • [in] arraybuffer: ArrayBuffer, лежащий в основе типизированного массива.
  • [in] byte_offset: Смещение байта в ArrayBuffer, с которого следует начать проецирование TypedArray.
  • [out] result: napi_value, представляющий JavaScript TypedArray.

Возвращает napi_ok, если API завершился успешно.

Этот API создает объект JavaScript TypedArray над существующим ArrayBuffer. Объекты TypedArray обеспечивают массивоподобное представление над базовым буфером данных, где каждый элемент имеет один и тот же базовый двоичный скалярный тип данных.

Требуется, чтобы (length * size_of_element) + byte_offset было \<= размеру в байтах передаваемого массива. Если это не так, то возникает исключение RangeError.

Объекты JavaScript TypedArray описаны в Раздел 22.2 спецификации языка ECMAScript.

napi_create_dataview.

1
2
3
4
5
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: ArrayBuffer, лежащий в основе DataView.
  • [in] byte_offset: Смещение байта в ArrayBuffer, с которого следует начать проецирование DataView.
  • [out] result: napi_value, представляющее JavaScript DataView.

Возвращает napi_ok, если API завершился успешно.

Этот API создает объект JavaScript DataView над существующим ArrayBuffer. Объекты DataView предоставляют представление, подобное массиву, над лежащим в основе буфером данных, но допускающее элементы разного размера и типа в ArrayBuffer.

Необходимо, чтобы byte_length + byte_offset было меньше или равно размеру в байтах передаваемого массива. В противном случае возникает исключение RangeError.

Объекты JavaScript DataView описаны в Раздел 24.3 спецификации языка ECMAScript.

Функции для преобразования типов C в Node-API

napi_create_int32

1
napi_status napi_create_int32(napi_env env, int32_t value, napi_value* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: Целочисленное значение, которое должно быть представлено в JavaScript.
  • [out] result: napi_value, представляющее в JavaScript число.

Возвращает napi_ok, если API прошел успешно.

Этот API используется для преобразования типа C int32_t в тип JavaScript number.

Тип JavaScript number описан в Раздел 6.1.6 спецификации языка ECMAScript.

napi_create_uint32.

1
napi_status napi_create_uint32(napi_env env, uint32_t value, napi_value* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: Беззнаковое целочисленное значение, которое будет представлено в JavaScript.
  • [out] result: napi_value, представляющее в JavaScript число.

Возвращает napi_ok, если API прошел успешно.

Этот API используется для преобразования типа C uint32_t в тип JavaScript number.

Тип JavaScript number описан в Раздел 6.1.6 спецификации языка ECMAScript.

napi_create_int64

1
napi_status napi_create_int64(napi_env env, int64_t value, napi_value* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: Целочисленное значение, которое должно быть представлено в JavaScript.
  • [out] result: napi_value, представляющее в JavaScript число.

Возвращает napi_ok, если API прошел успешно.

Этот API используется для преобразования типа C int64_t в тип JavaScript number.

Тип JavaScript number описан в Раздел 6.1.6 спецификации языка ECMAScript. Обратите внимание, что полный диапазон int64_t не может быть представлен с полной точностью в JavaScript. Целочисленные значения вне диапазона Number.MIN_SAFE_INTEGER -(2**53 - 1) - Number.MAX_SAFE_INTEGER (2**53 - 1) будут терять точность.

napi_create_double

1
napi_status napi_create_double(napi_env env, double value, napi_value* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: Значение двойной точности, которое должно быть представлено в JavaScript.
  • [out] result: napi_value, представляющее в JavaScript число.

Возвращает napi_ok, если API прошел успешно.

Этот API используется для преобразования типа C double в тип JavaScript number.

Тип JavaScript number описан в Раздел 6.1.6 спецификации языка ECMAScript.

napi_create_bigint_int64

1
2
3
napi_status napi_create_bigint_int64(napi_env env,
                                     int64_t value,
                                     napi_value* result);
  • [in] env: Среда, в которой вызывается API.
  • [in] value: Целочисленное значение, которое должно быть представлено в JavaScript.
  • [out] result: napi_value, представляющее в JavaScript BigInt.

Возвращает napi_ok, если API завершился успешно.

Этот API преобразует тип C int64_t в тип JavaScript BigInt.

napi_create_bigint_uint64.

1
2
3
napi_status napi_create_bigint_uint64(napi_env env,
                                      uint64_t value,
                                      napi_value* result);
  • [in] env: Среда, в которой вызывается API.
  • [in] value: Беззнаковое целочисленное значение, которое будет представлено в JavaScript.
  • [out] result: napi_value, представляющее JavaScript BigInt.

Возвращает napi_ok, если API прошел успешно.

Этот API преобразует тип C uint64_t в тип JavaScript BigInt.

napi_create_bigint_words.

1
2
3
4
5
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 little-endian 64-битных слов.
  • [out] result: Значение napi_value, представляющее JavaScript BigInt.

Возвращает napi_ok, если API завершился успешно.

Этот API преобразует массив беззнаковых 64-битных слов в одно значение BigInt.

Результирующее значение BigInt вычисляется как: (–1)sign_bit (words[0] × (264)0 + words[1] × (264)1 + …)

napi_create_string_latin1

1
2
3
4
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: Длина строки в байтах, или NAPI_AUTO_LENGTH, если она имеет нулевой конец.
  • [out] result: napi_value, представляющее JavaScript string.

Возвращает napi_ok, если API завершился успешно.

Этот API создает значение JavaScript string из ISO-8859-1-кодированной строки C. Родная строка копируется.

Тип JavaScript string описан в Раздел 6.1.4 спецификации языка ECMAScript.

napi_create_string_utf16.

1
2
3
4
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: Длина строки в двухбайтовых единицах кода, или NAPI_AUTO_LENGTH, если она является нуль-концевой.
  • [out] result: napi_value, представляющее JavaScript string.

Возвращает napi_ok, если API завершился успешно.

Этот API создает значение JavaScript string из строки C с кодировкой UTF16-LE. Родная строка копируется.

Тип JavaScript string описан в Раздел 6.1.4 спецификации языка ECMAScript.

napi_create_string_utf8.

1
2
3
4
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: Длина строки в байтах, или NAPI_AUTO_LENGTH, если она имеет нулевой конец.
  • [out] result: Значение napi_value, представляющее JavaScript строку.

Возвращает napi_ok, если API завершился успешно.

Этот API создает значение JavaScript string из строки C в кодировке UTF8. Родная строка копируется.

Тип JavaScript string описан в Раздел 6.1.4 спецификации языка ECMAScript.

Функции для преобразования типов Node-API в типы C

napi_get_array_length

1
2
3
napi_status napi_get_array_length(napi_env env,
                                  napi_value value,
                                  uint32_t* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: napi_value, представляющее JavaScript Array, длина которого запрашивается.
  • [out] result: uint32, представляющий длину массива.

Возвращает napi_ok, если API завершился успешно.

Этот API возвращает длину массива.

Длина массива описана в Раздел 22.1.4.1 спецификации языка ECMAScript.

napi_get_arraybuffer_info.

1
2
3
4
napi_status napi_get_arraybuffer_info(napi_env env,
                                      napi_value arraybuffer,
                                      void** data,
                                      size_t* byte_length)
  • [in] env: Среда, в которой вызывается API.
  • [in] arraybuffer: napi_value, представляющее запрашиваемый ArrayBuffer.
  • [out] data: Буфер данных, лежащий в основе ArrayBuffer. Если длина байта_length равна 0, это может быть NULL или любое другое значение указателя.
  • [out] byte_length: Длина в байтах основного буфера данных.

Возвращает napi_ok, если API прошел успешно.

Этот API используется для получения базового буфера данных ArrayBuffer и его длины.

WARNING: Будьте осторожны при использовании этого API. Время жизни базового буфера данных управляется ArrayBuffer даже после его возврата. Возможным безопасным способом использования этого API является использование в сочетании с napi_create_reference, который можно использовать для гарантированного контроля над временем жизни ArrayBuffer. Также безопасно использовать возвращенный буфер данных внутри одного и того же обратного вызова, если нет вызовов других API, которые могут вызвать GC.

napi_get_buffer_info.

1
2
3
4
napi_status napi_get_buffer_info(napi_env env,
                                 napi_value value,
                                 void** data,
                                 size_t* length)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: napi_value, представляющее запрашиваемый node::Buffer.
  • [out] data: Буфер данных, лежащий в основе node::Buffer. Если длина равна 0, это может быть NULL или любое другое значение указателя.
  • [out] length: Длина в байтах базового буфера данных.

Возвращает napi_ok, если API прошел успешно.

Этот API используется для получения базового буфера данных node::Buffer и его длины.

Предупреждение: Будьте осторожны при использовании этого API, поскольку время жизни базового буфера данных не гарантировано, если он управляется виртуальной машиной.

napi_get_prototype.

1
2
3
napi_status napi_get_prototype(napi_env env,
                               napi_value object,
                               napi_value* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] object: napi_value, представляющее JavaScript Object, прототип которого нужно вернуть. Возвращается эквивалент Object.getPrototypeOf (что не то же самое, что свойство prototype функции).
  • [out] result: napi_value, представляющее прототип данного объекта.

Возвращает napi_ok, если API прошел успешно.

napi_get_typedarray_info.

1
2
3
4
5
6
7
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: napi_value, представляющее TypedArray, свойства которого нужно запросить.
  • [out] type: Скалярный тип данных элементов в TypedArray.
  • [out] length: Количество элементов в TypedArray.
  • [out] data: Буфер данных, лежащий в основе TypedArray, скорректированный на значение byte_offset так, чтобы он указывал на первый элемент TypedArray. Если длина массива равна 0, это может быть NULL или любое другое значение указателя.
  • [out] arraybuffer: ArrayBuffer, лежащий в основе TypedArray.
  • [out] byte_offset: Смещение байта в базовом массиве, в котором находится первый элемент массива. Значение параметра data уже скорректировано таким образом, что data указывает на первый элемент массива. Поэтому первый байт исходного массива будет находиться по адресу data - byte_offset.

Возвращает napi_ok, если API прошел успешно.

Этот API возвращает различные свойства типизированного массива.

Любой из выводимых параметров может быть NULL, если это свойство не нужно.

Предупреждение: Будьте осторожны при использовании этого API, так как буфер данных, лежащий в основе, управляется виртуальной машиной.

napi_get_dataview_info.

1
2
3
4
5
6
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: napi_value, представляющее DataView, свойства которого нужно запросить.
  • [out] byte_length: Количество байтов в DataView.
  • [out] data: Буфер данных, лежащий в основе DataView. Если длина байта равна 0, это может быть NULL или любое другое значение указателя.
  • [out] arraybuffer: ArrayBuffer, лежащий в основе DataView.
  • [out] byte_offset: Смещение байта в буфере данных, с которого следует начать проецирование DataView.

Возвращает napi_ok, если API прошел успешно.

Любой из параметров out может быть NULL, если это свойство не нужно.

Этот API возвращает различные свойства DataView.

napi_get_date_value.

1
2
3
napi_status napi_get_date_value(napi_env env,
                                napi_value value,
                                double* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: napi_value, представляющее JavaScript Date.
  • [out] result: Значение времени в виде double, представленное в миллисекундах с полуночи в начале 01 января 1970 года по UTC.

Этот API не учитывает високосные секунды; они игнорируются, поскольку ECMAScript соответствует спецификации времени POSIX.

Возвращает napi_ok, если API прошел успешно. Если передано napi_value без даты, возвращается napi_date_expected.

Этот API возвращает примитив времени C double для заданной JavaScript Date.

napi_get_value_bool.

1
napi_status napi_get_value_bool(napi_env env, napi_value value, bool* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: napi_value, представляющее JavaScript Boolean.
  • [out] result: Булевский примитив, эквивалентный данному JavaScript Boolean.

Возвращает napi_ok, если API прошел успешно. Если передано небулевое napi_value, возвращается napi_boolean_expected.

Этот API возвращает примитивный эквивалент булевого значения на языке C для данного JavaScript Boolean.

napi_get_value_double.

1
2
3
napi_status napi_get_value_double(napi_env env,
                                  napi_value value,
                                  double* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: napi_value, представляющее JavaScript число.
  • [out] result: Двойной примитивный эквивалент данного JavaScript числа.

Возвращает napi_ok, если API прошел успешно. Если передано нечисловое napi_value, возвращается napi_number_expected.

Этот API возвращает двойной примитив C, эквивалентный заданному JavaScript числу.

napi_get_value_bigint_int64.

1
2
3
4
napi_status napi_get_value_bigint_int64(napi_env env,
                                        napi_value value,
                                        int64_t* result,
                                        bool* lossless);
  • [in] env: Среда, в которой вызывается API
  • [in] value: napi_value, представляющее JavaScript BigInt.
  • [out] result: Примитив C int64_t, эквивалентный данному JavaScript BigInt.
  • [out] lossless: Указывает, было ли значение BigInt преобразовано без потерь.

Возвращает napi_ok, если API прошел успешно. Если передано значение не BigInt, возвращается napi_bigint_expected.

Этот API возвращает примитивный эквивалент C int64_t заданного JavaScript BigInt. При необходимости он усекает значение, устанавливая lossless в false.

napi_get_value_bigint_uint64.

1
2
3
4
napi_status napi_get_value_bigint_uint64(napi_env env,
                                        napi_value value,
                                        uint64_t* result,
                                        bool* lossless);
  • [in] env: Среда, в которой вызывается API.
  • [in] value: napi_value, представляющее JavaScript BigInt.
  • [out] result: Примитив C uint64_t, эквивалентный данному JavaScript BigInt.
  • [out] lossless: Указывает, было ли значение BigInt преобразовано без потерь.

Возвращает napi_ok, если API прошел успешно. Если передано значение не BigInt, возвращается napi_bigint_expected.

Этот API возвращает примитивный эквивалент C uint64_t заданного JavaScript BigInt. При необходимости он усекает значение, устанавливая lossless в false.

napi_get_value_bigint_words.

1
2
3
4
5
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: napi_value, представляющее JavaScript BigInt.
  • [out] sign_bit: Целое число, представляющее, является ли JavaScript BigInt положительным или отрицательным.
  • [in/out] word_count: Должно быть инициализировано длиной массива words. По возвращении она будет установлена в фактическое количество слов, которое потребуется для хранения данного BigInt.
  • [out] words: Указатель на предварительно выделенный 64-битный массив слов.

Возвращает napi_ok, если API завершился успешно.

Этот API преобразует одно значение BigInt в знаковый бит, 64-битный little-endian массив, и количество элементов в массиве. Знак_бита" и words могут быть оба установлены в NULL, чтобы получить только word_count.

napi_get_value_external.

1
2
3
napi_status napi_get_value_external(napi_env env,
                                    napi_value value,
                                    void** result)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: napi_value, представляющее внешнее значение JavaScript.
  • [out] result: Указатель на данные, обернутые внешним значением JavaScript.

Возвращает napi_ok, если API прошел успешно. Если передано не внешнее napi_value, возвращается napi_invalid_arg.

Этот API извлекает указатель внешних данных, который был ранее передан в napi_create_external().

napi_get_value_int32.

1
2
3
napi_status napi_get_value_int32(napi_env env,
                                 napi_value value,
                                 int32_t* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: napi_value, представляющее JavaScript число.
  • [out] result: Примитивный эквивалент C int32 данного JavaScript числа.

Возвращает napi_ok, если API прошел успешно. Если в napi_number_expected передано нечисловое napi_number_value.

Этот API возвращает примитивный эквивалент C int32 заданного JavaScript числа.

Если число выходит за пределы диапазона 32-битного целого числа, то результат усекается до эквивалента нижних 32 бит. Это может привести к тому, что большое положительное число превратится в отрицательное, если значение > 231 - 1.

Значения не бесконечных чисел (NaN, +Infinity или -Infinity) устанавливают результат равным нулю.

napi_get_value_int64

1
2
3
napi_status napi_get_value_int64(napi_env env,
                                 napi_value value,
                                 int64_t* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: napi_value, представляющее JavaScript число.
  • [out] result: Примитивный эквивалент C int64 данного JavaScript числа.

Возвращает napi_ok, если API прошел успешно. Если передано нечисловое napi_value, возвращается napi_number_expected.

Этот API возвращает примитивный эквивалент C int64 заданного JavaScript number.

Значения чисел вне диапазона Number.MIN_SAFE_INTEGER -(2**53 - 1) - Number.MAX_SAFE_INTEGER (2**53 - 1) будут терять точность.

Значения не бесконечных чисел (NaN, +Infinity или -Infinity) устанавливают результат равным нулю.

napi_get_value_string_latin1

1
2
3
4
5
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: napi_value, представляющий строку JavaScript.
  • [in] buf: Буфер для записи строки в кодировке ISO-8859-1. Если передан NULL, то длина строки в байтах без учета нулевого терминатора возвращается в result.
  • [in] bufsize: Размер буфера назначения. Если это значение недостаточно, возвращаемая строка усекается и завершается нулем.
  • [out] result: Количество байт, скопированных в буфер, без учета нулевого терминатора.

Возвращает napi_ok, если API прошел успешно. Если передано не строковое napi_value, возвращается napi_string_expected.

Этот API возвращает строку в кодировке ISO-8859-1, соответствующую переданному значению.

napi_get_value_string_utf8.

1
2
3
4
5
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: napi_value, представляющий строку JavaScript.
  • [in] buf: Буфер для записи строки в UTF8-кодировке. Если передан NULL, то в result возвращается длина строки в байтах без учета нулевого терминатора.
  • [in] bufsize: Размер буфера назначения. Если это значение недостаточно, возвращаемая строка усекается и завершается нулем.
  • [out] result: Количество байт, скопированных в буфер, без учета нулевого терминатора.

Возвращает napi_ok, если API прошел успешно. Если передано нестроковое napi_value, возвращается napi_string_expected.

Этот API возвращает строку в кодировке UTF8, соответствующую переданному значению.

napi_get_value_string_utf16.

1
2
3
4
5
napi_status napi_get_value_string_utf16(napi_env env,
                                        napi_value value,
                                        char16_t* buf,
                                        size_t bufsize,
                                        size_t* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: napi_value, представляющий строку JavaScript.
  • [in] buf: Буфер для записи строки в кодировке UTF16-LE. Если передан NULL, то возвращается длина строки в 2-байтовых кодовых единицах и без учета нулевого терминатора.
  • [in] bufsize: Размер буфера назначения. Если это значение недостаточно, возвращаемая строка усекается и нуль-терминируется.
  • [out] result: Количество 2-байтовых единиц кода, скопированных в буфер, без учета нулевого терминатора.

Возвращает napi_ok, если API прошел успешно. Если передано не строковое napi_value, возвращается napi_string_expected.

Этот API возвращает строку в кодировке UTF16, соответствующую переданному значению.

napi_get_value_uint32.

1
2
3
napi_status napi_get_value_uint32(napi_env env,
                                  napi_value value,
                                  uint32_t* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: napi_value, представляющее JavaScript число.
  • [out] result: Примитивный эквивалент данного napi_value в виде uint32_t.

Возвращает napi_ok, если API прошел успешно. Если передано нечисловое napi_value, возвращается napi_number_expected.

Этот API возвращает примитивный эквивалент заданного napi_value в виде uint32_t.

Функции для получения глобальных экземпляров

napi_get_boolean.

1
napi_status napi_get_boolean(napi_env env, bool value, napi_value* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: Значение булевой величины для извлечения.
  • [out] result: napi_value, представляющий синглтон JavaScript Boolean для извлечения.

Возвращает napi_ok, если API прошел успешно.

Этот API используется для возврата объекта JavaScript singleton, который используется для представления заданного булева значения.

napi_get_global.

1
napi_status napi_get_global(napi_env env, napi_value* result)
  • [in] env: Среда, в которой вызывается API.
  • [out] result: napi_value, представляющий объект JavaScript global.

Возвращает napi_ok, если API завершился успешно.

Этот API возвращает объект global.

napi_get_null.

1
napi_status napi_get_null(napi_env env, napi_value* result)
  • [in] env: Среда, в которой вызывается API.
  • [out] result: napi_value, представляющий объект JavaScript null.

Возвращает napi_ok, если API завершился успешно.

Этот API возвращает объект null.

napi_get_undefined.

1
napi_status napi_get_undefined(napi_env env, napi_value* result)
  • [in] env: Среда, в которой вызывается API.
  • [out] result: napi_value, представляющее неопределенное значение JavaScript.

Возвращает napi_ok, если API завершился успешно.

Этот API возвращает объект Undefined.

Работа с JavaScript-значениями и абстрактными операциями

Node-API предоставляет набор API для выполнения некоторых абстрактных операций над значениями JavaScript. Некоторые из этих операций документированы в Разделе 7 Спецификации языка ECMAScript.

Эти API поддерживают выполнение одного из следующих действий:

  1. Приводить значения JavaScript к определенным типам JavaScript (таким как число или строка).
  2. Проверять тип значения JavaScript.
  3. Проверка равенства между двумя значениями JavaScript.

napi_coerce_to_bool.

1
2
3
napi_status napi_coerce_to_bool(napi_env env,
                                napi_value value,
                                napi_value* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: Значение JavaScript для когеренции.
  • [out] result: napi_value, представляющее принудительное JavaScript Boolean.

Возвращает napi_ok, если API завершился успешно.

Этот API реализует абстрактную операцию ToBoolean(), определенную в Раздел 7.1.2 спецификации языка ECMAScript.

napi_coerce_to_number

1
2
3
napi_status napi_coerce_to_number(napi_env env,
                                  napi_value value,
                                  napi_value* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: Значение JavaScript для когеренции.
  • [out] result: napi_value, представляющее принудительное JavaScript число.

Возвращает napi_ok, если API завершился успешно.

Этот API реализует абстрактную операцию ToNumber(), определенную в Раздел 7.1.3 спецификации языка ECMAScript. Эта функция потенциально запускает JS-код, если передаваемое значение является объектом.

napi_coerce_to_object

1
2
3
napi_status napi_coerce_to_object(napi_env env,
                                  napi_value value,
                                  napi_value* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: Значение JavaScript для когеренции.
  • [out] result: napi_value, представляющее когерентный JavaScript Object.

Возвращает napi_ok, если API завершился успешно.

Этот API реализует абстрактную операцию ToObject(), определенную в Section 7.1.13 спецификации языка ECMAScript.

napi_coerce_to_string.

1
2
3
napi_status napi_coerce_to_string(napi_env env,
                                  napi_value value,
                                  napi_value* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: Значение JavaScript для когеренции.
  • [out] result: napi_value, представляющее когерентную JavaScript строку.

Возвращает napi_ok, если API завершился успешно.

Этот API реализует абстрактную операцию ToString(), определенную в Section 7.1.13 спецификации языка ECMAScript. Эта функция потенциально запускает JS-код, если переданное значение является объектом.

napi_typeof

1
napi_status napi_typeof(napi_env env, napi_value value, napi_valuetype* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: Значение JavaScript, тип которого нужно запросить.
  • [out] result: Тип значения JavaScript.

Возвращает napi_ok, если API прошел успешно.

  • napi_invalid_arg, если тип value не является известным типом ECMAScript и value не является внешним значением.

Этот API представляет поведение, аналогичное вызову оператора typeof на объекте, как определено в Раздел 12.5.5 спецификации языка ECMAScript. Однако есть некоторые различия:

  1. В нем есть поддержка обнаружения внешнего значения.
  2. Он определяет null как отдельный тип, в то время как ECMAScript typeof будет определять object.

Если value имеет недопустимый тип, возвращается ошибка.

napi_instanceof.

1
2
3
4
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: Булево значение, которое устанавливается в true, если object instanceof constructor является true.

Возвращает napi_ok, если API прошел успешно.

Этот API представляет собой вызов оператора instanceof на объекте, как определено в Section 12.10.4 спецификации языка ECMAScript.

napi_is_array.

1
napi_status napi_is_array(napi_env env, napi_value value, bool* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: Значение JavaScript для проверки.
  • [out] result: Является ли данный объект массивом.

Возвращает napi_ok, если API прошел успешно.

Этот API представляет собой вызов операции IsArray над объектом, как определено в Раздел 7.2.2 спецификации языка ECMAScript.

napi_is_arraybuffer.

1
napi_status napi_is_arraybuffer(napi_env env, napi_value value, bool* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: Значение JavaScript для проверки.
  • [out] result: Является ли данный объект ArrayBuffer.

Возвращает napi_ok, если API прошел успешно.

Этот API проверяет, является ли переданный Объект буфером массива.

napi_is_buffer.

1
napi_status napi_is_buffer(napi_env env, napi_value value, bool* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: Значение JavaScript для проверки.
  • [out] result: Представляет ли данное napi_value объект node::Buffer.

Возвращает napi_ok, если API прошел успешно.

Этот API проверяет, является ли переданный Object буфером.

napi_is_date.

1
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.

Возвращает napi_ok, если API прошел успешно.

Этот API проверяет, является ли переданный Object датой.

napi_is_error.

1
napi_status napi_is_error(napi_env env, napi_value value, bool* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: Значение JavaScript для проверки.
  • [out] result: Представляет ли данное napi_value объект Error.

Возвращает napi_ok, если API завершился успешно.

Этот API проверяет, является ли переданный объект ошибкой.

napi_is_typedarray

1
napi_status napi_is_typedarray(napi_env env, napi_value value, bool* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: Значение JavaScript для проверки.
  • [out] result: Представляет ли данное napi_value TypedArray.

Возвращает napi_ok, если API прошел успешно.

Этот API проверяет, является ли переданный Object типизированным массивом.

napi_is_dataview

1
napi_status napi_is_dataview(napi_env env, napi_value value, bool* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] value: Значение JavaScript для проверки.
  • [out] result: Представляет ли данное napi_значение DataView.

Возвращает napi_ok, если API прошел успешно.

Этот API проверяет, является ли переданный объект DataView.

napi_strict_equals.

1
2
3
4
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.

Возвращает napi_ok, если API прошел успешно.

Этот API представляет собой вызов алгоритма Strict Equality, как определено в Section 7.2.14 спецификации языка ECMAScript.

napi_detach_arraybuffer.

1
2
napi_status napi_detach_arraybuffer(napi_env env,
                                    napi_value arraybuffer)
  • [in] env: Среда, в которой вызывается API.
  • [in] arraybuffer: JavaScript ArrayBuffer, который будет отсоединен.

Возвращает napi_ok, если API прошел успешно. Если передан неотделяемый ArrayBuffer, возвращается napi_detachable_arraybuffer_expected.

Как правило, ArrayBuffer является неотсоединяемым, если он уже был отсоединен ранее. Движок может накладывать дополнительные условия на то, является ли ArrayBuffer отсоединяемым. Например, V8 требует, чтобы ArrayBuffer был внешним, то есть созданным с помощью napi_create_external_arraybuffer.

Этот API представляет собой вызов операции отсоединения ArrayBuffer, как определено в Разделе 24.1.1.3 спецификации языка ECMAScript.

napi_is_detached_arraybuffer.

1
2
3
napi_status napi_is_detached_arraybuffer(napi_env env,
                                         napi_value arraybuffer,
                                         bool* result)
  • [in] env: Среда, в которой вызывается API.
  • [in] arraybuffer: JavaScript ArrayBuffer для проверки.
  • [out] result: Отсоединен ли массивный буфер.

Возвращает napi_ok, если API прошел успешно.

Буфер ArrayBuffer считается отсоединенным, если его внутренние данные равны null.

Этот API представляет собой вызов операции ArrayBuffer IsDetachedBuffer, как определено в Section 24.1.1.2 спецификации языка ECMAScript.

Работа со свойствами JavaScript

Node-API предоставляет набор API для получения и установки свойств объектов JavaScript. Некоторые из этих типов документированы в Разделе 7 Спецификации языка ECMAScript.

Свойства в JavaScript представлены в виде кортежа из ключа и значения. В принципе, все ключи свойств в Node-API могут быть представлены в одной из следующих форм:

  • Именованный: простая строка в кодировке UTF8.
  • Индексированный в целочисленном виде: значение индекса, представленное uint32_t.
  • Значение JavaScript: в Node-API они представлены napi_value. Это может быть napi_value, представляющее строку, число или символ.

Значения Node-API представлены типом napi_value. Любой вызов Node-API, требующий значения JavaScript, принимает napi_value. Однако вызывающая сторона несет ответственность за то, чтобы убедиться, что данное napi_value имеет тип JavaScript, ожидаемый API.

API, документированные в этом разделе, предоставляют простой интерфейс для получения и установки свойств произвольных объектов JavaScript, представленных napi_value.

Например, рассмотрим следующий фрагмент кода JavaScript:

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

Эквивалент может быть выполнен с использованием значений Node-API с помощью следующего фрагмента:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
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:

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

Эквивалент может быть выполнен с использованием значений Node-API с помощью следующего фрагмента:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
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:

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

Ниже приведен примерный эквивалент аналога Node-API:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
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, они соответствуют атрибутам, перечисленным в Разделе 6.1.7.1 Спецификации языка ECMAScript. Они могут быть одним или несколькими из следующих битовых флагов:

  • napi_default: Свойство не имеет явных атрибутов. По умолчанию свойство доступно только для чтения, не перечисляется и не настраивается.
  • napi_writable: Свойство доступно для записи.
  • napi_enumerable: Свойство можно перечислить.
  • napi_configurable: Свойство является настраиваемым, как определено в Section 6.1.7.1 ECMAScript Language Specification.
  • napi_static: Свойство будет определено как статическое свойство класса в отличие от свойства экземпляра, которое используется по умолчанию. Это используется только в napi_define_class. Оно игнорируется napi_define_properties.
  • napi_default_method: Как и метод в JS-классе, свойство настраивается и записывается, но не перечисляется.
  • napi_default_jsproperty: Как и свойство, заданное через присваивание в JavaScript, свойство доступно для записи, перечисляемо и настраиваемо.

napi_property_descriptor.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
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. Для свойства должно быть указано одно из utf8name или name.
  • name: Необязательное napi_value, указывающее на строку JavaScript или символ, который будет использоваться в качестве ключа для свойства. Для свойства должно быть указано одно из utf8name или name.
  • value: Значение, которое извлекается при получении доступа к свойству, если свойство является свойством данных. Если передано это значение, установите getter, setter, method и data в NULL (поскольку эти члены не будут использоваться).
  • getter: Функция, вызываемая при получении доступа к свойству. Если она передана, установите value и method в NULL (так как эти члены не будут использоваться). Данная функция неявно вызывается средой выполнения при обращении к свойству из кода JavaScript (или если get свойства выполняется с помощью вызова Node-API). napi_callback предоставляет более подробную информацию.
  • setter: Функция для вызова, когда выполняется доступ к свойству set. Если передается эта функция, установите value и method в NULL (так как эти члены не будут использоваться). Данная функция неявно вызывается средой выполнения, когда свойство устанавливается из кода JavaScript (или если установка свойства выполняется с помощью вызова Node-API). napi_callback предоставляет более подробную информацию.
  • method: Установите это значение, чтобы свойство value объекта дескриптора свойства было функцией JavaScript, представленной method. Если это свойство передано, установите value, getter и setter в NULL (поскольку эти члены не будут использоваться). napi_callback предоставляет более подробную информацию.
  • attributes: Атрибуты, связанные с конкретным свойством. См. napi_property_attributes.
  • data: Данные обратного вызова, передаваемые в method, getter и setter при вызове этой функции.

Функции

napi_get_property_names.

1
2
3
napi_status napi_get_property_names(napi_env env,
                                    napi_value object,
                                    napi_value* result);
  • [in] env: Среда, в которой вызывается вызов Node-API.
  • [in] object: Объект, из которого нужно получить свойства.
  • [out] result: napi_value, представляющий массив значений JavaScript, которые представляют имена свойств объекта. API можно использовать для итерации по result, используя napi_get_array_length и napi_get_element.

Возвращает napi_ok, если API завершился успешно.

Этот API возвращает имена перечислимых свойств object в виде массива строк. Свойства object, ключ которых является символом, не будут включены.

napi_get_all_property_names.

1
2
3
4
5
6
napi_get_all_property_names(napi_env env,
                            napi_value object,
                            napi_key_collection_mode key_mode,
                            napi_key_filter key_filter,
                            napi_key_conversion key_conversion,
                            napi_value* result);
  • [in] env: Среда, в которой вызывается вызов Node-API.
  • [in] object: Объект, из которого нужно получить свойства.
  • [in] key_mode: Получать ли свойства прототипа.
  • [in] key_filter: Какие свойства извлекать (перечислимые/читаемые/записываемые).
  • [in] key_conversion: Преобразовывать ли нумерованные ключи свойств в строки.
  • [out] result: napi_value, представляющий массив значений JavaScript, которые представляют имена свойств объекта. napi_get_array_length и napi_get_element могут быть использованы для итерации над result.

Возвращает napi_ok, если API завершился успешно.

Этот API возвращает массив, содержащий имена доступных свойств данного объекта.

napi_set_property.

1
2
3
4
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: Значение свойства.

Возвращает napi_ok, если API завершился успешно.

Этот API устанавливает свойство для переданного Объекта.

napi_get_property.

1
2
3
4
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: Значение свойства.

Возвращает napi_ok в случае успешного выполнения API.

Этот API получает запрошенное свойство из переданного Object.

napi_has_property.

1
2
3
4
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: Существует ли свойство у объекта или нет.

Возвращает napi_ok, если API завершился успешно.

Этот API проверяет, есть ли у переданного Object именованное свойство.

napi_delete_property.

1
2
3
4
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.

Возвращает napi_ok, если API завершился успешно.

Этот API пытается удалить собственное свойство key из object.

napi_has_own_property.

1
2
3
4
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: Существует ли собственное свойство у объекта или нет.

Возвращает napi_ok, если API завершился успешно.

Этот API проверяет, имеет ли переданный Object названное собственное свойство. key должно быть строкой или символом, иначе будет выдана ошибка. Node-API не будет выполнять никаких преобразований между типами данных.

napi_set_named_property.

1
2
3
4
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: Значение свойства.

Возвращает napi_ok, если API прошел успешно.

Этот метод эквивалентен вызову napi_set_property с napi_value, созданным из строки, переданной в качестве utf8Name.

napi_get_named_property.

1
2
3
4
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: Значение свойства.

Возвращает napi_ok, если API прошел успешно.

Этот метод эквивалентен вызову napi_get_property с napi_value, созданным из строки, переданной в качестве utf8Name.

napi_has_named_property.

1
2
3
4
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: Существует ли свойство у объекта или нет.

Возвращает napi_ok, если API прошел успешно.

Этот метод эквивалентен вызову napi_has_property с napi_value, созданным из строки, переданной в качестве utf8Name.

napi_set_element.

1
2
3
4
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: Значение свойства.

Возвращает napi_ok, если API прошел успешно.

Этот API устанавливает элемент на переданном Object.

napi_get_element.

1
2
3
4
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: Значение свойства.

Возвращает napi_ok, если API завершился успешно.

Этот API получает элемент по запрошенному индексу.

napi_has_element.

1
2
3
4
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: Существует ли свойство у объекта или нет.

Возвращает napi_ok в случае успешного выполнения API.

Этот API возвращает, если переданный Object имеет элемент по запрошенному индексу.

napi_delete_element.

1
2
3
4
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.

Возвращает napi_ok, если API завершился успешно.

Этот API пытается удалить указанный index из object.

napi_define_properties.

1
2
3
4
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: Количество элементов в массиве свойств.
  • [in] properties: Массив дескрипторов свойств.

Возвращает napi_ok, если API прошел успешно.

Этот метод позволяет эффективно определить несколько свойств для данного объекта. Свойства определяются с помощью дескрипторов свойств (см. napi_property_descriptor). Учитывая массив таких дескрипторов свойств, данный API будет устанавливать свойства объекта по одному за раз, как определено в DefineOwnProperty() (описано в Раздел 9.1.6 спецификации ECMA-262).

napi_object_freeze.

1
2
napi_status napi_object_freeze(napi_env env,
                               napi_value object);
  • [in] env: Среда, в которой вызывается вызов Node-API.
  • [in] object: Объект, который нужно заморозить.

Возвращает napi_ok, если API прошел успешно.

Этот метод замораживает заданный объект. Это предотвращает добавление к нему новых свойств, удаление существующих свойств, предотвращает изменение перечислимости, конфигурируемости или возможности записи существующих свойств, а также предотвращает изменение значений существующих свойств. Также предотвращается изменение прототипа объекта. Это описано в Раздел 19.1.2.6 спецификации ECMA-262.

napi_object_seal.

1
2
napi_status napi_object_seal(napi_env env,
                             napi_value object);
  • [in] env: Среда, в которой вызывается вызов Node-API.
  • [in] object: Объект, который нужно запечатать.

Возвращает napi_ok, если API прошел успешно.

Этот метод запечатывает заданный объект. Это предотвращает добавление к нему новых свойств, а также помечает все существующие свойства как неконфигурируемые. Это описано в Section 19.1.2.20 спецификации ECMA-262.

Работа с функциями JavaScript

Node-API предоставляет набор API, которые позволяют JavaScript-коду обращаться к родному коду. Node-API, поддерживающие обратный вызов в родной код, принимают функции обратного вызова, представленные типом napi_callback. Когда JavaScript VM обращается к родному коду, вызывается предоставленная функция napi_callback. API, документированные в этом разделе, позволяют функции обратного вызова делать следующее:

  • Получить информацию о контексте, в котором был вызван обратный вызов.
  • Получить аргументы, переданные в обратный вызов.
  • Возвращать napi_value обратно из обратного вызова.

Кроме того, Node-API предоставляет набор функций, которые позволяют вызывать функции JavaScript из родного кода. Функцию можно вызывать как обычную функцию JavaScript или как функцию-конструктор.

Любые неNULL данные, которые передаются в этот API через поле data элементов napi_property_descriptor, могут быть связаны с object и освобождаться всякий раз, когда object очищается от мусора, путем передачи object и данных в napi_add_finalizer.

napi_call_function.

1
2
3
4
5
6
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: napi_value, представляющее вызываемую функцию JavaScript.
  • [in] argc: Количество элементов в массиве argv.
  • [in] argv: Массив napi_values, представляющий значения JavaScript, переданные в качестве аргументов функции.
  • [out] result: napi_value, представляющий возвращаемый объект JavaScript.

Возвращает napi_ok, если API прошел успешно.

Этот метод позволяет вызывать объект функции JavaScript из родного дополнения. Это основной механизм обратного вызова из родного кода дополнения в JavaScript. Для особого случая вызова JavaScript после асинхронной операции смотрите napi_make_callback.

Пример использования может выглядеть следующим образом. Рассмотрим следующий фрагмент JavaScript:

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

Затем вышеуказанную функцию можно вызвать из родного дополнения с помощью следующего кода:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 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

1
2
3
4
5
6
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] length: Длина utf8name в байтах, или NAPI_AUTO_LENGTH, если оно нуль-концевое.
  • [in] cb: Родная функция, которая должна быть вызвана при вызове этого объекта функции. napi_callback предоставляет более подробную информацию.
  • [in] data: Предоставляемый пользователем контекст данных. Он будет передан обратно в функцию при последующем вызове.
  • [out] result: napi_value, представляющий объект функции JavaScript для вновь созданной функции.

Возвращает napi_ok, если API прошел успешно.

Этот API позволяет автору дополнения создать объект функции в родном коде. Это основной механизм, позволяющий вызывать внутри родного кода дополнения из JavaScript.

Вновь созданная функция не становится автоматически видимой из сценария после этого вызова. Вместо этого необходимо явно установить свойство для любого объекта, видимого JavaScript, чтобы функция была доступна из сценария.

Для того чтобы выставить функцию как часть экспорта модуля дополнения, установите вновь созданную функцию на объект exports. Пример модуля может выглядеть следующим образом:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
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 следующим образом:

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

Строка, переданная в require(), является именем цели в binding.gyp, ответственной за создание файла .node.

Любые неNULLданные, которые передаются этому API через параметр data, могут быть связаны с результирующей функцией JavaScript (которая возвращается в параметре result) и освобождаться всякий раз, когда функция очищается от мусора, передавая и функцию JavaScript, и данные в napi_add_finalizer.

JavaScript функции описаны в Раздел 19.2 спецификации языка ECMAScript.

napi_get_cb_info.

1
2
3
4
5
6
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 и получает фактическое количество аргументов. По желанию argc можно проигнорировать, передав NULL.
  • [out] argv: Массив napi_value, в который будут скопированы аргументы. Если аргументов больше, чем указано, то копируется только запрошенное количество аргументов. Если предоставлено меньше аргументов, чем заявлено, остальная часть argv заполняется значениями napi_value, которые представляют собой неопределенные. По желанию argv можно игнорировать, передав NULL.
  • [out] thisArg: Получает аргумент JavaScript this для вызова. По желанию thisArg можно игнорировать, передавая NULL.
  • [out] data: Получает указатель данных для обратного вызова. При желании data можно игнорировать, передав NULL.

Возвращает napi_ok, если API прошел успешно.

Этот метод используется в функции обратного вызова для получения подробной информации о вызове, например, аргументов и указателя this из данного обратного вызова.

napi_get_new_target

1
2
3
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 вызова конструктора.

Возвращает napi_ok, если API завершился успешно.

Этот API возвращает new.target вызова конструктора. Если текущий обратный вызов не является вызовом конструктора, результатом будет NULL.

napi_new_instance

1
2
3
4
5
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: napi_value, представляющее функцию JavaScript, которая будет вызвана в качестве конструктора.
  • [in] argc: Количество элементов в массиве argv.
  • [in] argv: Массив значений JavaScript в формате napi_value, представляющий аргументы конструктора. Если argc равен нулю, этот параметр можно опустить, передав NULL.
  • [out] result: napi_value, представляющее возвращаемый объект JavaScript, который в данном случае является сконструированным объектом.

Этот метод используется для инстанцирования нового значения JavaScript с помощью заданного napi_value, представляющего конструктор для объекта. Например, рассмотрим следующий фрагмент:

1
2
3
4
5
6
function MyObject(param) {
    this.param = param;
}

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

Следующее можно аппроксимировать в Node-API с помощью следующего фрагмента:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// 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);

Возвращает napi_ok, если API прошел успешно.

Обертывание объектов

Node-API предлагает способ "обернуть" классы и экземпляры C++ так, чтобы конструктор класса и методы можно было вызывать из JavaScript.

  1. API napi_define_class определяет класс JavaScript с конструктором, статическими свойствами и методами, а также свойствами и методами экземпляра, которые соответствуют классу C++.
  2. Когда код JavaScript вызывает конструктор, обратный вызов конструктора использует napi_wrap для обертывания нового экземпляра C++ в объект JavaScript, а затем возвращает объект-обертку.
  3. Когда код JavaScript вызывает метод или аксессор свойства класса, вызывается соответствующая функция C++ napi_callback. Для обратного вызова экземпляра napi_unwrap получает экземпляр C++, который является целью вызова.

Для обернутых объектов может быть трудно отличить функцию, вызванную на прототипе класса, от функции, вызванной на экземпляре класса. Для решения этой проблемы обычно используется сохранение постоянной ссылки на конструктор класса для последующих проверок instanceof.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
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 в методах прототипа. В таких случаях есть вероятность, что они могут быть развернуты неправильно.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
const myAddon = require('./build/Release/my_addon.node');

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

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

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

В приведенном выше примере myAddon.queryHasRecords() - это метод, принимающий два аргумента. Первый - это хэндл базы данных, а второй - хэндл запроса. Внутри метода он разворачивает первый аргумент и приводит полученный указатель к собственному дескриптору базы данных. Затем он разворачивает второй аргумент и приводит полученный указатель к дескриптору запроса. Если аргументы переданы в неправильном порядке, приведение будет работать, однако велика вероятность, что базовая операция с базой данных завершится неудачно или даже вызовет некорректный доступ к памяти.

Чтобы убедиться, что указатель, полученный из первого аргумента, действительно является указателем на дескриптор базы данных и, аналогично, что указатель, полученный из второго аргумента, действительно является указателем на дескриптор запроса, реализация queryHasRecords() должна выполнить проверку типа. Сохранение в napi_ref конструктора класса JavaScript, из которого был создан дескриптор базы данных, и конструктора, из которого был создан дескриптор запроса, может помочь, поскольку napi_instanceof() может быть использовано для проверки того, что экземпляры, переданные в queryHashRecords(), действительно имеют правильный тип.

К сожалению, napi_instanceof() не защищает от манипуляций с прототипом. Например, прототип экземпляра handle базы данных может быть установлен на прототип конструктора для экземпляров query handle. В этом случае экземпляр дескриптора базы данных может выглядеть как экземпляр дескриптора запроса, и он пройдет тест napi_instanceof() для экземпляра дескриптора запроса, но при этом будет содержать указатель на дескриптор базы данных.

Для этого Node-API предоставляет возможность тегирования типов.

Метка типа - это 128-битное целое число, уникальное для аддона. Node-API предоставляет структуру napi_type_tag для хранения метки типа. Когда такое значение передается вместе с объектом JavaScript, хранящимся в napi_value, в napi_type_tag_object(), объект JavaScript будет "помечен" тегом типа. Эта "метка" невидима на стороне JavaScript. Когда объект JavaScript поступает в родную привязку, napi_check_object_type_tag() может использоваться вместе с исходным тегом типа, чтобы определить, был ли объект JavaScript ранее "помечен" тегом типа. Это создает возможность проверки типа с более высокой точностью, чем napi_instanceof() может обеспечить, потому что такая проверка типа сохраняет манипуляции с прототипом и выгрузку/перезагрузку аддонов.

Продолжая приведенный выше пример, следующая скелетная реализация аддона иллюстрирует использование napi_type_tag_object() и napi_check_object_type_tag().

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// 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

1
2
3
4
5
6
7
8
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] length: Длина utf8name в байтах, или NAPI_AUTO_LENGTH, если она нуль-терминирована.
  • [in] constructor: Функция обратного вызова, которая обрабатывает создание экземпляров класса. При обертывании класса C++ этот метод должен быть статическим членом с сигнатурой napi_callback. Конструктор класса C++ не может быть использован. napi_callback предоставляет более подробную информацию.
  • [in] data: Необязательные данные, которые будут переданы обратному вызову конструктора в качестве свойства data обратного вызова.
  • [in] property_count: Количество элементов в массиве properties аргумента.
  • [in] properties: Массив дескрипторов свойств, описывающих статические свойства и свойства данных экземпляра, аксессоры и методы класса См. napi_property_descriptor.
  • [out] result: Значение napi_value, представляющее функцию конструктора для класса.

Возвращает napi_ok, если API прошел успешно.

Определяет класс JavaScript, включая:

  • Функцию-конструктор JavaScript, которая имеет имя класса. При обертывании соответствующего класса C++ обратный вызов, переданный через constructor, может быть использован для инстанцирования нового экземпляра класса C++, который затем может быть помещен внутрь конструируемого экземпляра объекта JavaScript с помощью napi_wrap.
  • Свойства функции-конструктора, реализация которых может вызывать соответствующие статические свойства данных, аксессоры и методы класса C++ (определяемые дескрипторами свойств с атрибутом napi_static).
  • Свойства объекта prototype функции-конструктора. При обертывании класса C++ нестатические свойства данных, аксессоры и методы класса C++ могут быть вызваны из статических функций, заданных в описателях свойств без атрибута napi_static, после извлечения экземпляра класса C++, размещенного внутри экземпляра объекта JavaScript, с помощью napi_unwrap.

При обертывании класса C++ обратный вызов конструктора C++, переданный через constructor, должен быть статическим методом класса, который вызывает фактический конструктор класса, затем оборачивает новый экземпляр C++ в объект JavaScript и возвращает объект-обертку. Подробности смотрите в napi_wrap.

Функция-конструктор JavaScript, возвращаемая из napi_define_class, часто сохраняется и используется позже для создания новых экземпляров класса из собственного кода, и/или для проверки того, являются ли предоставленные значения экземплярами класса. В этом случае, чтобы предотвратить сбор мусора, можно создать сильную постоянную ссылку на значение функции с помощью napi_create_reference, гарантируя, что количество ссылок сохраняется >= 1.

Любые неNULLданные, которые передаются этому API через параметр data или через поле data в `napi_propert

napi_wrap.

1
2
3
4
5
6
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: Экземпляр native, который будет обернут в объект JavaScript.
  • [in] finalize_cb: Необязательный обратный вызов native, который может быть использован для освобождения native экземпляра, когда JavaScript объект будет очищен от мусора. napi_finalize предоставляет более подробную информацию.
  • [in] finalize_hint: Необязательная контекстная подсказка, которая передается обратному вызову finalize.
  • [out] result: Необязательная ссылка на обернутый объект.

Возвращает napi_ok, если API прошел успешно.

Обертывает нативный экземпляр в объект JavaScript. Нативный объект может быть получен позже с помощью napi_unwrap().

Когда JavaScript код вызывает конструктор для класса, который был определен с помощью napi_define_class(), вызывается napi_callback для конструктора. После создания экземпляра собственного класса обратный вызов должен вызвать napi_wrap(), чтобы завернуть созданный экземпляр в уже созданный объект JavaScript, который является аргументом this для обратного вызова конструктора. (Этот объект this был создан на основе прототипа функции конструктора, поэтому он уже имеет определения всех свойств и методов экземпляра).

Обычно при обертывании экземпляра класса следует предусмотреть обратный вызов finalize, который просто удаляет собственный экземпляр, полученный в качестве аргумента data обратного вызова finalize.

Необязательная возвращаемая ссылка изначально является слабой ссылкой, то есть имеет счетчик ссылок 0. Обычно этот счетчик ссылок временно увеличивается во время асинхронных операций, требующих, чтобы экземпляр оставался действительным.

Предупреждение: Необязательная возвращаемая ссылка (если она получена) должна быть удалена через napi_delete_reference ТОЛЬКО в ответ на вызов обратного вызова finalize. Если она будет удалена до этого, то обратный вызов finalize может никогда не быть вызван. Поэтому при получении ссылки также требуется обратный вызов finalize, чтобы обеспечить корректное удаление ссылки.

Обратные вызовы финализатора могут быть отложены, оставляя окно, в котором объект был собран (и слабая ссылка недействительна), но финализатор еще не был вызван. При использовании napi_get_reference_value() для слабых ссылок, возвращаемых napi_wrap(), вы должны обрабатывать пустой результат.

Вызов napi_wrap() во второй раз для объекта вернет ошибку. Чтобы связать с объектом другой нативный экземпляр, сначала используйте napi_remove_wrap().

napi_unwrap.

1
2
3
napi_status napi_unwrap(napi_env env,
                        napi_value js_object,
                        void** result);
  • [in] env: Среда, в которой вызывается API.
  • [in] js_object: Объект, связанный с нативным экземпляром.
  • [out] result: Указатель на обернутый нативный экземпляр.

Возвращает napi_ok, если API прошел успешно.

Извлекает нативный экземпляр, который ранее был обернут в объект JavaScript с помощью napi_wrap().

Когда код JavaScript вызывает метод или аксессор свойства класса, вызывается соответствующий napi_callback. Если обратный вызов предназначен для метода или доступа к экземпляру, то аргументом this обратного вызова является объект-обертка; обернутый экземпляр C++, который является целью вызова, можно получить, вызвав napi_unwrap() на объекте-обертке.

napi_remove_wrap

1
2
3
napi_status napi_remove_wrap(napi_env env,
                             napi_value js_object,
                             void** result);
  • [in] env: Среда, в которой вызывается API.
  • [in] js_object: Объект, связанный с нативным экземпляром.
  • [out] result: Указатель на обернутый нативный экземпляр.

Возвращает napi_ok, если API прошел успешно.

Получает нативный экземпляр, который ранее был обернут в объект JavaScript js_object с помощью napi_wrap() и удаляет обертку. Если с оберткой был связан обратный вызов finalize, он больше не будет вызываться, когда объект JavaScript станет очищенным от мусора.

napi_type_tag_object.

1
2
3
napi_status napi_type_tag_object(napi_env env,
                                 napi_value js_object,
                                 const napi_type_tag* type_tag);
  • [in] env: Среда, в которой вызывается API.
  • [in] js_object: Объект JavaScript, который должен быть помечен.
  • [in] type_tag: Тег, которым должен быть помечен объект.

Возвращает napi_ok, если API прошел успешно.

Ассоциирует значение указателя type_tag с объектом JavaScript. napi_check_object_type_tag() может затем использоваться для сравнения тега, который был прикреплен к объекту, с тегом, принадлежащим аддону, чтобы убедиться, что объект имеет правильный тип.

Если у объекта уже есть связанный тег типа, этот API вернет napi_invalid_arg.

napi_check_object_type_tag.

1
2
3
4
napi_status napi_check_object_type_tag(napi_env env,
                                       napi_value js_object,
                                       const napi_type_tag* type_tag,
                                       bool* result);
  • [in] env: Среда, в которой вызывается API.
  • [in] js_object: Объект JavaScript, тег типа которого необходимо проверить.
  • [in] type_tag: Тег, с которым нужно сравнить любой тег, найденный на объекте.
  • [out] result: Совпадает ли заданный тег типа с тегом типа объекта. Также возвращается false, если тег типа не был найден на объекте.

Возвращает napi_ok, если API прошел успешно.

Сравнивает указатель, заданный как type_tag, с любым, который может быть найден на js_object. Если тег не найден на js_object или, если тег найден, но не соответствует type_tag, то result устанавливается в false. Если тег найден и он соответствует type_tag, то result устанавливается в true.

napi_add_finalizer.

1
2
3
4
5
6
napi_status napi_add_finalizer(napi_env env,
                               napi_value js_object,
                               void* finalize_data,
                               napi_finalize finalize_cb,
                               void* finalize_hint,
                               napi_ref* result);
  • [in] env: Среда, в которой вызывается API.
  • [in] js_object: Объект JavaScript, к которому будут присоединены нативные данные.
  • [in] finalize_data: Необязательные данные для передачи в finalize_cb.
  • [in] finalize_cb: Нативный обратный вызов, который будет использоваться для освобождения нативных данных, когда объект JavaScript будет очищен от мусора. napi_finalize предоставляет более подробную информацию.
  • [in] finalize_hint: Необязательная контекстная подсказка, которая передается обратному вызову finalize.
  • [out] result: Необязательная ссылка на объект JavaScript.

Возвращает napi_ok, если API прошел успешно.

Добавляет обратный вызов napi_finalize, который будет вызван, когда объект JavaScript в js_object будет очищен от мусора.

Этот API может быть вызван несколько раз для одного объекта JavaScript.

Внимание: Необязательная возвращаемая ссылка (если она получена) должна быть удалена через napi_delete_reference ТОЛЬКО в ответ на вызов обратного вызова finalize. Если она будет удалена до этого, то обратный вызов finalize может никогда не быть вызван. Поэтому при получении ссылки также требуется обратный вызов finalize, чтобы обеспечить корректное удаление ссылки.

Простые асинхронные операции

Модули аддонов часто нуждаются в использовании асинхронных помощников из libuv как части своей реализации. Это позволяет им планировать выполнение работы асинхронно, чтобы их методы могли возвращаться до завершения работы. Это позволяет им избежать блокировки общего выполнения приложения Node.js.

Node-API предоставляет ABI-стабильный интерфейс для этих вспомогательных функций, который охватывает наиболее распространенные случаи асинхронного использования.

Node-API определяет структуру napi_async_work, которая используется для управления асинхронными рабочими. Экземпляры создаются/удаляются с помощью функций napi_create_async_work и napi_delete_async_work.

Обратные вызовы execute и complete - это функции, которые будут вызваны, когда исполнитель будет готов к выполнению и когда он завершит свою задачу соответственно.

Функция execute должна избегать любых вызовов Node-API, которые могут привести к выполнению JavaScript или взаимодействию с объектами JavaScript. Чаще всего, любой код, который должен выполнять вызовы Node-API, должен выполняться в обратном вызове complete. Избегайте использования параметра napi_env в обратном вызове execute, так как это может привести к выполнению JavaScript.

Эти функции реализуют следующие интерфейсы:

1
2
3
4
5
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:

1
2
napi_status napi_queue_async_work(napi_env env,
                                  napi_async_work work);

napi_cancel_async_work можно использовать, если работу нужно отменить до того, как она начала выполняться.

После вызова napi_cancel_async_work будет вызван обратный вызов complete со значением статуса napi_cancelled. Работа не должна быть удалена до вызова обратного вызова complete, даже если она была отменена.

napi_create_async_work

1
2
3
4
5
6
7
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: Идентификатор типа ресурса, который предоставляется для диагностической информации, раскрываемой API async_hooks.
  • [in] execute: Собственная функция, которая должна быть вызвана для асинхронного выполнения логики. Данная функция вызывается из потока рабочего пула и может выполняться параллельно с основным потоком цикла событий.
  • [in] complete: Собственная функция, которая будет вызвана, когда асинхронная логика будет завершена или отменена. Данная функция вызывается из главного потока цикла событий. napi_async_complete_callback предоставляет более подробную информацию.
  • [in] data: Предоставляемый пользователем контекст данных. Он будет передан обратно в функции execute и complete.
  • [out] result: napi_async_work*, который является хэндлом только что созданной асинхронной работы.

Возвращает napi_ok, если API завершился успешно.

Этот API выделяет объект work, который используется для асинхронного выполнения логики. Он должен быть освобожден с помощью napi_delete_async_work, когда работа больше не нужна.

Имя ресурса async_resource_name должно быть нуль-терминированной строкой в кодировке UTF-8.

Идентификатор async_resource_name предоставляется пользователем и должен отражать тип выполняемой асинхронной работы. Также рекомендуется применять пространство имен к идентификатору, например, включая имя модуля. Дополнительную информацию см. в документации async_hooks.

napi_delete_async_work.

1
2
napi_status napi_delete_async_work(napi_env env,
                                   napi_async_work work);
  • [in] env: Среда, в которой вызывается API.
  • [in] work: Хендл, возвращенный вызовом napi_create_async_work.

Возвращает napi_ok, если API завершился успешно.

Этот API освобождает ранее выделенный объект work.

Этот API может быть вызван, даже если есть ожидающее исключение JavaScript.

napi_queue_async_work.

1
2
napi_status napi_queue_async_work(napi_env env,
                                  napi_async_work work);
  • [in] env: Среда, в которой вызывается API.
  • [in] work: Хендл, возвращенный вызовом napi_create_async_work.

Возвращает napi_ok, если API завершился успешно.

Этот API запрашивает, чтобы ранее выделенная работа была запланирована для выполнения. После успешного возврата этот API не должен вызываться снова с тем же элементом napi_async_work, иначе результат будет неопределен.

napi_cancel_async_work.

1
2
napi_status napi_cancel_async_work(napi_env env,
                                   napi_async_work work);
  • [in] env: Среда, в которой вызывается API.
  • [in] work: Хендл, возвращенный вызовом napi_create_async_work.

Возвращает napi_ok, если API завершился успешно.

Этот API отменяет постановку работы в очередь, если она еще не была начата. Если она уже начала выполняться, она не может быть отменена и будет возвращена napi_generic_failure. В случае успеха будет вызван обратный вызов complete со значением статуса napi_cancelled. Работа не должна быть удалена до вызова обратного вызова complete, даже если она была успешно отменена.

Этот API может быть вызван даже при наличии ожидающего исключения JavaScript.

Пользовательские асинхронные операции

Приведенные выше простые API асинхронной работы могут подойти не для каждого сценария. При использовании любого другого асинхронного механизма, следующие API необходимы для того, чтобы асинхронная операция правильно отслеживалась средой выполнения.

napi_async_init.

1
2
3
4
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: Идентификатор вида ресурса, который предоставляется для диагностической информации, раскрываемой API async_hooks.
  • [out] result: Инициализированный асинхронный контекст.

Возвращает napi_ok, если API завершился успешно.

Объект async_resource необходимо поддерживать живым до napi_async_destroy, чтобы API, связанные с async_hooks, работали корректно. Для сохранения совместимости ABI с предыдущими версиями, napi_async_context не поддерживает сильную ссылку на объекты async_resource, чтобы избежать утечек памяти. Однако, если async_resource был собран в мусор движком JavaScript до того, как napi_async_context был уничтожен командой napi_async_destroy, вызов связанных с napi_async_context API, таких как napi_open_callback_scope и napi_make_callback может вызвать проблемы, такие как потеря асинхронного контекста при использовании API AsyncLocalStorage.

Чтобы сохранить совместимость ABI с предыдущими версиями, передача NULL для async_resource не приводит к ошибке. Однако это не рекомендуется, так как это приведет к плохим результатам при использовании async_hooks init hooks и async_hooks.executionAsyncResource(), так как ресурс теперь требуется базовой реализации async_hooks для обеспечения связи между обратными вызовами async.

napi_async_destroy.

1
2
napi_status napi_async_destroy(napi_env env,
                               napi_async_context async_context);
  • [in] env: Среда, в которой вызывается API.
  • [in] async_context: Асинхронный контекст, который должен быть уничтожен.

Возвращает napi_ok, если API завершился успешно.

Этот API может быть вызван, даже если есть ожидающее исключение JavaScript.

napi_make_callback.

1
2
3
4
5
6
7
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 с предыдущими версиями, передача NULL для async_context не приводит к ошибке. Однако это приводит к некорректной работе асинхронных хуков. Потенциальные проблемы включают потерю асинхронного контекста при использовании API AsyncLocalStorage.
  • [in] recv: Значение this, переданное вызываемой функции.
  • [in] func: napi_value, представляющее вызываемую функцию JavaScript.
  • [in] argc: Количество элементов в массиве argv.
  • [in] argv: Массив значений JavaScript в виде napi_value, представляющих аргументы функции. Если argc равен нулю, этот параметр можно опустить, передав NULL.
  • [out] result: napi_value, представляющее возвращаемый объект JavaScript.

Возвращает napi_ok, если API прошел успешно.

Этот метод позволяет вызывать объект функции JavaScript из встроенного дополнения. Этот API аналогичен napi_call_function. Однако он используется для вызова из нативного кода обратно в JavaScript после возврата из асинхронной операции (когда в стеке нет другого сценария). Это довольно простая обертка вокруг node::MakeCallback.

Обратите внимание, что не нужно использовать napi_make_callback внутри napi_async_complete_callback; в этой ситуации асинхронный контекст обратного вызова уже установлен, поэтому достаточно прямого вызова napi_call_function. Использование функции napi_make_callback может потребоваться при реализации пользовательского асинхронного поведения, которое не использует napi_create_async_work.

Любые process.nextTick или Promises, запланированные в очереди микрозадач JavaScript во время обратного вызова, выполняются перед возвратом обратно в C/C++.

napi_open_callback_scope.

1
2
3
4
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. Этот параметр был устаревшим и игнорируется во время выполнения. Вместо него используйте параметр async_resource в napi_async_init.
  • [in] context: Контекст для асинхронной операции, которая вызывает обратный вызов. Это должно быть значение, полученное ранее из napi_async_init.
  • [out] result: Вновь созданная область видимости.

Бывают случаи (например, разрешение обещаний), когда при выполнении определенных вызовов Node-API необходимо иметь эквивалент области видимости, связанной с обратным вызовом. Если в стеке нет другого скрипта, то для открытия/закрытия нужного диапазона можно использовать функции napi_open_callback_scope и napi_close_callback_scope.

napi_close_callback_scope.

1
2
NAPI_EXTERN napi_status napi_close_callback_scope(napi_env env,
                                                  napi_callback_scope scope)
  • [in] env: Среда, в которой вызывается API.
  • [in] scope: Область видимости, которую нужно закрыть.

Этот API может быть вызван, даже если есть ожидающее исключение JavaScript.

Управление версиями

napi_get_node_version.

1
2
3
4
5
6
7
8
9
typedef struct {
  uint32_t major;
  uint32_t minor;
  uint32_t patch;
  const char* release;
} napi_node_version;

napi_status napi_get_node_version(napi_env env,
                                  const napi_node_version** version);
  • [in] env: Среда, в которой вызывается API.
  • [out] version: Указатель на информацию о версии самого Node.js.

Возвращает napi_ok, если API прошел успешно.

Эта функция заполняет структуру version мажорной, минорной и патч-версией Node.js, которая запущена в данный момент, а поле release - значением process.release.name.

Возвращаемый буфер выделяется статически и не требует освобождения.

napi_get_version

1
2
napi_status napi_get_version(napi_env env,
                             uint32_t* result);
  • [in] env: Среда, в которой вызывается API.
  • [out] result: Наивысшая версия Node-API, которая поддерживается.

Возвращает napi_ok, если API завершился успешно.

Этот API возвращает самую высокую версию Node-API, поддерживаемую средой выполнения Node.js. Планируется, что Node-API будет аддитивным, так что новые выпуски Node.js могут поддерживать дополнительные функции API. Для того чтобы позволить аддону использовать более новую функцию при работе с версиями Node.js, которые ее поддерживают, обеспечивая при этом запасное поведение при работе с версиями Node.js, которые ее не поддерживают:

  • Вызовите napi_get_version(), чтобы определить, доступен ли API.
  • Если он доступен, динамически загрузите указатель на функцию с помощью uv_dlsym().
  • Используйте динамически загруженный указатель для вызова функции.
  • Если функция недоступна, предоставьте альтернативную реализацию, которая не использует эту функцию.

Управление памятью

napi_adjust_external_memory

1
2
3
NAPI_EXTERN napi_status napi_adjust_external_memory(napi_env env,
                                                    int64_t change_in_bytes,
                                                    int64_t* result);
  • [in] env: Среда, в которой вызывается API.
  • [in] change_in_bytes: Изменение во внешней выделенной памяти, которая поддерживается объектами JavaScript.
  • [out] result: Скорректированное значение.

Возвращает napi_ok, если API прошел успешно.

Эта функция дает V8 представление об объеме внешней выделенной памяти, которая поддерживается объектами JavaScript (т.е. объектом JavaScript, который указывает на собственную память, выделенную родным аддоном). Регистрация выделенной извне памяти будет вызывать глобальные сборки мусора чаще, чем в противном случае.

Обещания

Node-API предоставляет средства для создания объектов Promise, как описано в Раздел 25.4 спецификации ECMA. Он реализует обещания как пару объектов. Когда обещание создается с помощью napi_create_promise(), создается "отложенный" объект, который возвращается вместе с Promise. Отложенный объект связан с созданным Promise и является единственным средством для разрешения или отклонения Promise с помощью napi_resolve_deferred() или napi_reject_deferred(). Отложенный объект, созданный napi_create_promise(), освобождается napi_resolve_deferred() или napi_reject_deferred(). Объект Promise может быть возвращен в JavaScript, где он может быть использован обычным образом.

Например, чтобы создать обещание и передать его асинхронному рабочему:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
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() выполнит свое асинхронное действие, а затем разрешит или отклонит отложенное, тем самым завершив обещание и освободив отложенное:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
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

1
2
3
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() для разрешения или отклонения связанного обещания.
  • [out] promise: Обещание JavaScript, связанное с отложенным объектом.

Возвращает napi_ok, если API завершился успешно.

Этот API создает отложенный объект и обещание JavaScript.

napi_resolve_deferred.

1
2
3
napi_status napi_resolve_deferred(napi_env env,
                                  napi_deferred deferred,
                                  napi_value resolution);
  • [in] env: Среда, в которой вызывается API.
  • [in] deferred: Отложенный объект, чье связанное обещание нужно разрешить.
  • [in] resolution: Значение, с которым нужно разрешить обещание.

Этот API разрешает обещание JavaScript посредством отложенного объекта, с которым оно связано. Таким образом, его можно использовать только для разрешения обещаний JavaScript, для которых доступен соответствующий отложенный объект. Это означает, что обещание должно быть создано с помощью napi_create_promise(), а отложенный объект, возвращенный в результате этого вызова, должен быть сохранен, чтобы быть переданным этому API.

Отложенный объект освобождается при успешном завершении.

napi_reject_deferred

1
2
3
napi_status napi_reject_deferred(napi_env env,
                                 napi_deferred deferred,
                                 napi_value rejection);
  • [in] env: Среда, в которой вызывается API.
  • [in] deferred: Отложенный объект, чье связанное обещание нужно разрешить.
  • [in] rejection: Значение, с которым следует отклонить обещание.

Этот API отклоняет обещание JavaScript посредством отложенного объекта, с которым оно связано. Таким образом, его можно использовать только для отклонения обещаний JavaScript, для которых доступен соответствующий отложенный объект. Это фактически означает, что обещание должно быть создано с помощью napi_create_promise(), а отложенный объект, возвращенный этим вызовом, должен быть сохранен, чтобы быть переданным этому API.

Отложенный объект освобождается при успешном завершении.

napi_is_promise

1
2
3
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.

1
2
3
NAPI_EXTERN napi_status napi_run_script(napi_env env,
                                        napi_value script,
                                        napi_value* result);
  • [in] env: Среда, в которой вызывается API.
  • [in] script: Строка JavaScript, содержащая сценарий для выполнения.
  • [out] result: Значение, полученное в результате выполнения сценария.

Эта функция выполняет строку кода JavaScript и возвращает результат со следующими оговорками:

  • В отличие от eval, эта функция не позволяет скрипту получить доступ к текущей лексической области видимости, а значит и к области видимости модуля, что означает, что псевдо-глобалы, такие как require, будут недоступны.
  • Скрипт может получить доступ к глобальной области видимости. Объявления функций и var в скрипте будут добавлены к объекту global. Объявления переменных, сделанные с помощью let и const, будут видны глобально, но не будут добавлены в объект global.
  • Значение this - global внутри сценария.

цикл событий libuv

Node-API предоставляет функцию для получения текущего цикла событий, связанного с определенным napi_env.

napi_get_uv_event_loop.

1
2
NAPI_EXTERN napi_status napi_get_uv_event_loop(napi_env env,
                                               struct uv_loop_s** loop);
  • [in] env: Среда, в которой вызывается API.
  • [out] loop: Текущий экземпляр цикла libuv.

Асинхронные потокобезопасные вызовы функций

Функции JavaScript обычно могут быть вызваны только из главного потока аддона. Если аддон создает дополнительные потоки, то функции Node-API, требующие napi_env, napi_value или napi_ref, не должны вызываться из этих потоков.

Когда аддон имеет дополнительные потоки и функции JavaScript должны быть вызваны на основе обработки, завершенной этими потоками, эти потоки должны взаимодействовать с главным потоком аддона, чтобы главный поток мог вызвать функцию JavaScript от их имени. API потокобезопасных функций предоставляют простой способ сделать это.

Эти API предоставляют тип napi_threadsafe_function, а также API для создания, уничтожения и вызова объектов этого типа. napi_create_threadsafe_function() создает постоянную ссылку на napi_value, содержащую функцию JavaScript, которая может быть вызвана из нескольких потоков. Вызовы происходят асинхронно. Это означает, что значения, с которыми должен быть вызван обратный вызов JavaScript, будут помещены в очередь, и для каждого значения в очереди будет сделан вызов функции JavaScript.

При создании napi_threadsafe_function может быть предусмотрен обратный вызов napi_finalize. Этот обратный вызов будет вызван в главном потоке, когда потокобезопасная функция будет уничтожена. Он получает контекст и данные finalize, переданные при построении, и предоставляет возможность очистить потоки, например, вызвав uv_thread_join(). *После завершения обратного вызова finalize ни один поток, кроме основного потока цикла, не должен использовать потокобезопасную функцию.

Контекст, переданный при вызове napi_create_threadsafe_function(), может быть получен из любого потока вызовом 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 блокирует очередь до тех пор, пока в ней не освободится место. napi_call_threadsafe_function() никогда не блокируется, если потокобезопасная функция была создана с максимальным размером очереди 0.

napi_call_threadsafe_function() не должна вызываться с napi_tsfn_blocking из потока JavaScript, поскольку, если очередь переполнена, это может привести к тупику потока JavaScript.

Фактический вызов JavaScript контролируется обратным вызовом, заданным через параметр call_js_cb. call_js_cb вызывается в основном потоке один раз для каждого значения, которое было помещено в очередь в результате успешного вызова napi_call_threadsafe_function(). Если такой обратный вызов не задан, то в главном потоке вызывается def

Обратный вызов также может быть вызван с env и call_js_cb, установленными в NULL, чтобы указать, что вызовы JavaScript больше невозможны, а в очереди остаются элементы, которые могут быть освобождены. Обычно это происходит, когда процесс Node.js завершается, а потокобезопасная функция все еще активна.

Нет необходимости обращаться к JavaScript через napi_make_callback(), поскольку Node-API запускает call_js_cb в контексте, подходящем для обратных вызовов.

Подсчет ссылок на потокобезопасные функции

Потоки могут быть добавлены и удалены из объекта napi_threadsafe_function во время его существования. Таким образом, помимо указания начального количества потоков при создании, можно вызвать napi_acquire_threadsafe_function, чтобы указать, что новый поток начнет использовать потокобезопасную функцию. Аналогично, napi_release_threadsafe_function может быть вызвана, чтобы указать, что существующий поток перестанет использовать потокобезопасную функцию.

Объекты napi_threadsafe_function уничтожаются, когда каждый поток, использующий объект, вызвал napi_release_threadsafe_function() или получил статус возврата napi_closing в ответ на вызов napi_call_threadsafe_function. Очередь опустошается перед уничтожением napi_threadsafe_function. napi_release_threadsafe_function() должен быть последним вызовом API, сделанным в связи с данной napi_threadsafe_function, потому что после завершения вызова нет гарантии, что napi_threadsafe_function все еще выделена. По этой же причине не используйте потокобезопасную функцию после получения возвращаемого значения napi_closing в ответ на вызов napi_call_threadsafe_function. Данные, связанные с napi_threadsafe_function, могут быть освобождены в ее обратном вызове napi_finalize, который был передан в napi_create_threadsafe_function(). Параметр initial_thread_count из napi_create_threadsafe_function отмечает начальное количество приобретений потокобезопасных функций, вместо того, чтобы вызывать 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_closing из napi_call_threadsafe_function() поток не должен больше использовать потокобезопасную функцию, поскольку выделение средств больше не гарантируется..

Решение о том, следует ли продолжать процесс.

Подобно дескрипторам libuv, потокобезопасные функции могут быть "ссылающимися" и "нессылающимися". Функция потокобезопасности "со ссылкой" заставит цикл событий в потоке, в котором она создана, оставаться живым до тех пор, пока функция потокобезопасности не будет уничтожена. В отличие от нее, "нессылочная" потокобезопасная функция не будет препятствовать выходу цикла событий. Для этого существуют API napi_ref_threadsafe_function и napi_unref_threadsafe_function.

Ни napi_unref_threadsafe_function не помечает потокобезопасные функции как способные быть уничтоженными, ни napi_ref_threadsafe_function не предотвращает их уничтожение.

napi_create_threadsafe_function

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
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 для предоставления идентификатора типа ресурса, который предоставляется для диагностической информации, раскрываемой API async_hooks.
  • [in] max_queue_size: Максимальный размер очереди. 0 для отсутствия ограничений.
  • [in] initial_thread_count: Начальное количество приобретений, т.е. начальное количество потоков, включая основной поток, которые будут использовать эту функцию.
  • [in] thread_finalize_data: Необязательные данные для передачи в thread_finalize_cb.
  • [in] thread_finalize_cb: Необязательная функция для вызова при уничтожении napi_threadsafe_function.
  • [in] context: Необязательные данные для присоединения к полученной napi_threadsafe_function.
  • [in] call_js_cb: Необязательный обратный вызов, который вызывает функцию JavaScript в ответ на вызов в другом потоке. Этот обратный вызов будет вызван в основном потоке. Если он не указан, функция JavaScript будет вызвана без параметров и с undefined в качестве значения this. napi_threadsafe_function_call_js предоставляет более подробную информацию.
  • [out] result: Асинхронная потокобезопасная функция JavaScript.

napi_get_threadsafe_function_context.

1
2
3
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.

1
2
3
4
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, когда очередь заполнена.

Этот API не должен вызываться с napi_tsfn_blocking из потока JavaScript, потому что, если очередь заполнена, это может привести к тупику потока JavaScript.

Этот API вернет napi_closing, если napi_release_threadsafe_function() была вызвана с abort, установленным в napi_tsfn_abort из любого потока. Значение добавляется в очередь, только если API возвращает napi_ok.

Этот API может быть вызван из любого потока, который использует func.

napi_acquire_threadsafe_function

1
2
NAPI_EXTERN napi_status
napi_acquire_threadsafe_function(napi_threadsafe_function func);
  • [in] func: Асинхронная потокобезопасная функция JavaScript для начала использования.

Поток должен вызвать этот API перед передачей func другим API потокобезопасных функций, чтобы указать, что он будет использовать func. Это предотвращает уничтожение func, когда все остальные потоки перестали ее использовать.

Этот API может быть вызван из любого потока, который начнет использовать func.

napi_release_threadsafe_function

1
2
3
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, и никакие дальнейшие значения не будут помещаться в очередь.

Поток должен вызывать этот API, когда он перестает использовать func. Передача func в любой потокобезопасный API после вызова этого API приводит к неопределенным результатам, так как func может быть уничтожен.

Этот API может быть вызван из любого потока, который перестанет использовать func.

napi_ref_threadsafe_function

1
2
NAPI_EXTERN napi_status
napi_ref_threadsafe_function(napi_env env, napi_threadsafe_function func);
  • [in] env: Среда, в которой вызывается API.
  • [in] func: Потокобезопасная функция, на которую нужно сослаться.

Этот API используется для указания того, что цикл событий, запущенный в главном потоке, не должен завершаться до тех пор, пока func не будет уничтожена. Подобно uv_ref он также является идемпотентным.

Ни napi_unref_threadsafe_function не помечает потокобезопасные функции как способные быть уничтоженными, ни napi_ref_threadsafe_function не предотвращает их уничтожение. Для этого доступны napi_acquire_threadsafe_function и napi_release_threadsafe_function.

Этот API может быть вызван только из главного потока.

napi_unref_threadsafe_function

1
2
NAPI_EXTERN napi_status
napi_unref_threadsafe_function(napi_env env, napi_threadsafe_function func);
  • [in] env: Среда, в которой вызывается API.
  • [in] func: Потокобезопасная функция для отсылки.

Этот API используется для указания того, что цикл событий, запущенный в главном потоке, может завершиться до того, как func будет уничтожена. Подобно uv_unref, он также является идемпотентным.

Этот API может быть вызван только из главного потока.

Разные утилиты

node_api_get_module_file_name.

Стабильность: 1 – Экспериментальная

Фича изменяется и не допускается флагом командной строки. Может быть изменена или удалена в последующих версиях.

1
2
NAPI_EXTERN napi_status
node_api_get_module_file_name(napi_env env, const char** result);
  • [in] env: Среда, в которой вызывается API.
  • [out] result: URL-адрес, содержащий абсолютный путь к месту, из которого было загружено дополнение. Для файла в локальной файловой системе он будет начинаться с file://. Строка является нуль-терминированной и принадлежит env, поэтому не должна быть изменена или освобождена.

result может быть пустой строкой, если процесс загрузки дополнения не смог определить имя файла дополнения во время загрузки.