Node8.0 之 Napi 探祕

本文目錄

  • 簡介
  • Napi簡介
  • 鐵打的hello_world
  • 關於文件頭
  • 關於基礎數據類型
  • 關於錯誤處理
  • 關於異常處理
    • 相關異常處理函數
  • 關於生命週期
    • 相關函數
    • 關於模塊註冊
  • 關於js的類型值
    • 枚舉值
    • 對象構造器
    • C->N-api值 轉換函數
    • N-api->C 值轉換函數
    • 獲取全局實例的函數
    • 關於JavaScript值的抽象操做
  • 關於JavaScript中的屬性
    • 官方示例
    • 索引值的demo
    • 複雜對象的demo
    • 相關結構體
    • 相關函數
  • JavaScript函數相關
  • 關於對象包裹
  • 關於異步操做

簡介

最近發生了不少事,node終於迎來了8.1.0的更新,同時rust語言也迎來了他的1.18版本,帶來了更多的更新。不過這裏主要想要敘述的仍是關於node的新特性napi。因爲找了下網上的教程基本都止步於官網的hello_world的demo的成功運行,因此想用本身淺薄的英語知識去啃一下深刻的東西。
javascript

Napi簡介

因爲大部分的二進制node模塊都嚴重依賴於V8引擎的暴露的接口,一旦v8引擎有所變更,就會致使模塊的使用出現問題。因此按照程序員通用的思路,既然依賴太強,那就抽象一層吧,因此node官方作了這麼一層抽象,使程序員不用直接面對V8引擎,而是使用node抽象出來的一層接口,這樣保證了在各個版本之間模塊的通用性等等。嗯,這段話是小生本身寫的,不對之處請指出Orz。html

鐵打的hello_world

講道理,這段示例其實在各個文章中都大同小異,相信各個看官都看過好幾遍了,不過爲了文章的連貫性,小生仍是不得再也不寫一次。java

首先,咱們更新node到8.1.0或以上版本node

node --versionc++

而後咱們全局安裝node-gyp,小生用的yarn,因此就用yarn安裝了程序員

yarn global add node-gypes6

安裝成功後咱們新建一個文件夾來作實驗npm

mkdir napi
cd napi
yarn init -y json

yarn初始化項目的方式是init -y,npm是 init -f,不過這個其實沒啥子,主要是初始化package.json而已。而後咱們按照之前和之前寫二進制模塊同樣的方式,先創建src目錄,創建.cc文件,而後創建binding.gyp文件api

mkdir src
touch src/hello.cc
touch binding.gyp

而後咱們編輯hello.cc,這裏直接使用官方的demo了:

#include <node_api.h>

// 實際暴露的方法,這裏只是簡單返回一個字符串
napi_value HelloMethod (napi_env env, napi_callback_info info) {
    napi_value world;
    napi_create_string_utf8(env, "world", 5, &world);
    return world;
}

// 擴展的初始化方法,其中 
// env:環境變量
// exports、module:node模塊中對外暴露的對象
void Init (napi_env env, napi_value exports, napi_value module, void* priv) {
    // napi_property_descriptor 爲結構體,做用是描述擴展暴露的 屬性/方法 的描述
    napi_property_descriptor desc = { "hello", 0, HelloMethod, 0, 0, 0, napi_default, 0 };
    napi_define_properties(env, exports, 1, &desc);  // 定義暴露的方法
}

NAPI_MODULE(hello, Init);  // 註冊擴展,擴展名叫作hello,Init爲擴展的初始化方法複製代碼

而後咱們編輯binding.gyp:

{
  "targets": [
    {
      "target_name": "hello",
      "sources": [ "./src/hello.cc" ]
    }
  ]
}複製代碼

接下來直接:

node-gyp rebuild

就能夠看到本地多出了build文件夾,而且能夠發現編譯後的文件build/Release/hello.node,因此咱們能夠直接寫一個js文件測試咱們的demo是否成功了:

//index.js
var a=require('./build/Release/hello')
console.log(a.hello())複製代碼

運行

node --napi-modules index.js

後發現輸出world,即一切正常,咱們完成了一個二進制包的編寫。因爲目前napi還屬於新特性階段,因此運行時須要加上--napi-modules參數。恩,大多數的文章就到此爲止了,不太小生仍是決定看看官方的api,深刻研究下。

官網文檔的研究

因爲文檔很長,無法一次看完慢慢整理,因此小生一邊看文檔,一邊思索一邊測試一邊寫,內容可能會有一點小小的混亂,請見諒。napi文檔傳送門

關於文件頭

因爲napi是新特性,因此在運行時請加上參數--napi-modules,同時在cc文件中需加上#include <node_api.h>頭部

關於基礎數據類型

  • napi_status是一個枚舉數據類型,爲了節省篇幅,具體定義請點擊後與官網查看,該數據類型表示一個napi函數調用是否成功,每當調用一個napi的函數後,都會返回該值,表示是否操做的成功與否信息,例:
napi_value result;
napi_status status = napi_get_element(e object, i, &result);
if (status != napi_ok) {
  //do someting
}複製代碼

其中napi_ok就是napi_status的枚舉取值之一,表示操做成功

  • napi_extended_error_info是一個結構體,在調用函數不成功時存儲了較爲詳細的錯誤信息

  • napi_env表示一個上下文的變量

  • napi_value是對全部js的基本值的一個密閉封裝,簡單來講,就是表示一個基本值

  • napi_handle_scope,這是一個抽象類型,用於管理和修改在特定範圍內建立的對象的生命週期,使用napi_open_handle_scope將創建一個上下文環境使用napi_close_handle_scope將關閉這個上下文環境,在關閉這個上下文後,全部在其中聲明的引用都將被關閉。說的簡單點,就是相似於給包了一個大括弧,全部的let屬性聲明週期都只能在這內部。

  • napi_escapable_handle_scope是一個將特定範圍內聲明的值返回到父做用域的一個特殊類型

  • napi_ref是一個抽象類型,用於引用napi_value,讓用戶能管理js值的生命週期

  • napi_callback_info這是傳遞給回調函數的一個封裝的數據類型,能夠用於獲取有關調用時的上下文信息,也能夠用於設置回調函數的返回值

  • 經過Napi暴露給用戶設置的回調函數指針,設置回調應該知足如下函數簽名:

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

  • napi_async_execute_callbacknapi_async_complete_callback兩者皆是與回調函數一塊兒運行的函數指針,函數簽名須要知足如下:

    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);

關於錯誤處理

全部的napi函數都使用相同的錯誤處理函數,在調用以後會返回napi_status,在不出錯正常時會返回napi_ok,若是隻是拋出異常,則會返回napi_pending_exception,在二者皆不是的狀況下須要使用napi_is_exception_pending來判斷是否有異常被掛起。當有錯誤發生時,則須要使用函數napi_get_last_error_info,該函數會將錯誤信息填充到參數napi_extended_error_info中,函數簽名以下:

NAPI_EXTERN napi_status napi_get_last_error_info(napi_env env,const napi_extended_error_info** result);

調用後會返回該次調用的napi_status,若是結果是napi_ok,那麼result參數將會被填充成napi_extended_error_info結構體,該結構體以下:

typedef struct napi_extended_error_info {
const char error_message;
void
engine_reserved;
uint32_t engine_error_code;
napi_status error_code;
};

關於異常處理

在使用napi_is_exception_pending肯定有異常掛起後,有兩種方式來處理異常。第一種,也是官方推薦的一種,就是簡單處理後直接返回,使代碼觸發js內的異常,交由js自行處理。第二種,是不推薦的,就是嘗試自行處理異常,可使用napi_get_and_clear_last_exception來獲取以及清除異常。不過在檢索後,發現沒法處理該異常,能夠選擇[napi_throw] []來從新拋出該異常。

相關異常處理函數

  • napi_throw

    NODE_EXTERN napi_status napi_throw(napi_env env, napi_value error);

    該函數返回一個js可接受的錯誤

  • napi_throw_error

    NODE_EXTERN napi_status napi_throw_error(napi_env env, const char* msg);

    該函數拋出一個純文本的錯誤信息

  • napi_throw_type_error

    NODE_EXTERN napi_status napi_throw_type_error(napi_env env, const char* msg);

    該函數拋出一個純文本的類型錯誤信息

  • napi_throw_range_error

    NODE_EXTERN napi_status napi_throw_range_error(napi_env env, const char* msg);

    該函數拋出一個純文本的RangeError

  • napi_is_error

    NODE_EXTERN napi_status napi_is_error(napi_env env,napi_value value,bool* result);

    該函數會檢查傳入的napi_value是不是一個錯誤對象

  • napi_create_error

    NODE_EXTERN napi_status napi_create_error(napi_env env, const char* msg);

    該函數會返回一個js純文本錯誤

  • napi_create_type_error

    NODE_EXTERN napi_status napi_create_type_error(napi_env env, const char* msg);

    該函數會返回一個js純文本類型錯誤

  • napi_create_range_error

    NODE_EXTERN napi_status napi_create_range_error(napi_env env, const char* msg);

    該函數會返回一個js純文本RangeError

  • napi_get_and_clear_last_exception

    NAPI_EXTERN napi_status napi_get_and_clear_last_exception(napi_env env,napi_value* result);

    這裏官方文檔應該是寫錯了,官方文檔函數描述是This API returns true if an exception is pending.,很明顯,這個描述是錯的,從前文來看,該函數的效果應該是獲取最近的一次的句柄,而且清除異常

  • napi_is_exception_pending

    NAPI_EXTERN napi_status napi_is_exception_pending(napi_env env, bool* result);

    這裏官方的描述依舊是This API returns true if an exception is pending.,不過這下就正常了,該函數會在有異常被掛起時返回true

關於生命週期

因爲在napi中全部js相關的值都是一個不透明的分裝,默認生命週期是和全局一致的,有時候處於安全和性能的考慮,須要將一些值得生命週期限制在必定的範圍之內,此時就須要用到上文提到過得open_handle_scope和napi_close_handle_scope來建立和關閉一個上下文環境。示例:

for (int i = 0; i < 1000000; i++) {
  napi_handle_scope scope;
  napi_status status = napi_open_handle_scope(env, &scope);
  if (status != napi_ok) {
    break;
  }
  napi_value result;
  status = napi_get_element(e object, i, &result);
  if (status != napi_ok) {
    break;
  }
  // do something with element
  status = napi_close_handle_scope(env, scope);
  if (status != napi_ok) {
    break;
  }
}複製代碼

此時,因爲限制了做用域,因此每一個result的生命週期都被限制在了單次循環以內。
在有些時候某些值得生命週期須要大於自己所在區域的週期時,能夠將他們放在 napi_open_escapable_handle_scopenapi_close_escapable_handle_scope這兩個函數之間,此間定義的值的生命週期將與父級的做用域的生命週期一致,而不侷限於自己的生命週期。

相關函數簽名:

> NODE_EXTERN napi_status napi_open_handle_scope(napi_env env,napi_handle_scope* result);

> NODE_EXTERN napi_status napi_close_handle_scope(napi_env env,napi_handle_scope scope);

> NODE_EXTERN napi_status napi_open_escapable_handle_scope(napi_env env,napi_handle_scope* result);

> NODE_EXTERN napi_status napi_close_escapable_handle_scope(napi_env env,napi_handle_scope scope);

> NAPI_EXTERN napi_status napi_escape_handle(napi_env env,napi_escapable_handle_scope scope,napi_value escapee,napi_value* result);複製代碼

關於模塊註冊:

Napi的模塊註冊使用NAPI_MODULE(addon, Init)方式來註冊,其中Init方法簽名以下:

void Init(napi_env env, napi_value exports, napi_value module, void* priv);

關於js的類型值

Napi建立了一系列的api來負責建立各類類型的JavaScript值。這系列api主要用於如下功能:

  • 建立一個新的JavaScript對象
  • 從原始的c類型轉換到N-api值
  • 從N-api值轉換爲原始的c類型
  • 獲取全局實例,包括undefined和null

枚舉值

  • napi_valuetype
typedef enum {
  // ES6 types (corresponds to typeof)
  napi_undefined,
  napi_null,
  napi_boolean,
  napi_number,
  napi_string,
  napi_symbol,
  napi_object,
  napi_function,
  napi_external,
} napi_valuetype;複製代碼
  • napi_typedarray_type
typedef enum {
  napi_int8_array,
  napi_uint8_array,
  napi_uint8_clamped_array,
  napi_int16_array,
  napi_uint16_array,
  napi_int32_array,
  napi_uint32_array,
  napi_float32_array,
  napi_float64_array,
} napi_typedarray_type;複製代碼

對象構造器

  • napi_create_array

    napi_status napi_create_array(napi_env env, napi_value* result)

    該函數返回一個JavaScript數組類型對應的napi值

  • napi_create_array_with_length

    napi_status napi_create_array_with_length(napi_env env,size_t length,napi_value* result)

    該函數返回特定長度的JavaScript數組類型對應的napi值,可是該函數不能保證在建立陣列時由VM預先分配內存,若是須要保證緩衝區必須是能夠經過c直接讀取或寫入的連續的內存,須要使用napi_create_external_arraybuffer

  • napi_create_arraybuffer

    napi_status napi_create_arraybuffer(napi_env env,size_t byte_length,void* data,napi_value result)

  • napi_create_buffer

    napi_status napi_create_buffer(napi_env env,size_t size,void* data,napi_value result)

  • napi_create_buffer_copy

    napi_status napi_create_buffer_copy(napi_env env,size_t length,const void data,void** result_data,napi_value result)

  • napi_create_external

    napi_status napi_create_external(napi_env env,void data,napi_finalize finalize_cb,void finalize_hint,napi_value* result)

  • napi_create_external_arraybuffer

    napi_status napi_create_external_arraybuffer(napi_env env,void external_data,size_t byte_length,napi_finalize finalize_cb,void finalize_hint,napi_value* result)

  • napi_create_external_buffer

    napi_status napi_create_external_buffer(napi_env env,size_t length,void data,napi_finalize finalize_cb,void finalize_hint,napi_value* result)

  • napi_create_function

    napi_status napi_create_function(napi_env env,const char utf8name,napi_callback cb,void data,napi_value* result)

    該函數返回JavaScript中函數對應的napi值,用於包裝本地函數,使JavaScript能夠調用它

  • napi_create_object

    napi_status napi_create_object(napi_env env, napi_value* result)

    該函數返回一個默認的JavaScript對象,等同於在JavaScript中調用new Object()

  • napi_create_symbol

    api_status napi_create_symbol(napi_env env,const char description,napi_value result)

  • napi_create_typedarray

    napi_status napi_create_typedarray(napi_env env,napi_typedarray_type type,size_t length,napi_value arraybuffer,size_t byte_offset,napi_value* result)

C->N-api值 轉換函數

  • napi_create_number

    napi_status napi_create_number(napi_env env, double value, napi_value* result)

  • napi_create_string_utf16

    napi_status napi_create_string_utf16(napi_env env,const char16_t str,size_t length,napi_value result)

  • napi_create_string_utf8

    napi_status napi_create_string_utf8(napi_env env,const char str,size_t length,napi_value result)

N-api->C 值轉換函數

  • napi_get_array_length

    napi_status napi_get_array_length(napi_env env,napi_value value,uint32_t* result)

  • napi_get_arraybuffer_info

    napi_status napi_get_arraybuffer_info(napi_env env,napi_value arraybuffer,void* data,size_t byte_length)

  • napi_get_buffer_info

    napi_status napi_get_buffer_info(napi_env env,napi_value value,void* data,size_t length)

  • napi_get_prototype

    napi_status napi_get_prototype(napi_env env,napi_value object,napi_value* result)

  • napi_get_typedarray_info

    napi_status napi_get_typedarray_info(napi_env env,napi_value typedarray,napi_typedarray_type type,size_t length,void* data,napi_value arraybuffer,size_t* byte_offset)

  • napi_get_value_bool

    napi_status napi_get_value_bool(napi_env env, napi_value value, bool* result)

  • napi_get_value_double

    napi_status napi_get_value_double(napi_env env,napi_value value,double* result)

  • napi_get_value_external

    napi_status napi_get_value_external(napi_env env,napi_value value,void** result)

  • napi_get_value_int32

    napi_status napi_get_value_int32(napi_env env,napi_value value,int32_t* result)

  • napi_get_value_int64

    napi_status napi_get_value_int64(napi_env env,napi_value value,int64_t* result)

  • napi_get_value_string_length

    napi_status napi_get_value_string_length(napi_env env,napi_value value,int* result)

  • napi_get_value_string_utf8

    napi_status napi_get_value_string_utf8(napi_env env,napi_value value,char buf,size_t bufsize,size_t result)

  • napi_get_value_string_utf16

    napi_status napi_get_value_string_utf16(napi_env env,napi_value value,char16_t buf,size_t bufsize,size_t result)

  • napi_get_value_uint32

    napi_status napi_get_value_uint32(napi_env env,napi_value value,uint32_t* result)

獲取全局實例的函數

  • napi_get_boolean

    napi_status napi_get_boolean(napi_env env, bool value, napi_value* result)

  • napi_get_global

    napi_status napi_get_global(napi_env env, napi_value* result)

  • napi_get_null

    napi_status napi_get_null(napi_env env, napi_value* result)

  • napi_get_undefined

    napi_status napi_get_undefined(napi_env env, napi_value* result)

關於JavaScript值的抽象操做

  • napi_coerce_to_bool

    napi_status napi_coerce_to_bool(napi_env env,napi_value value,napi_value* result)

    對於JavaScript中的ToBoolean操做的一個實現

  • napi_coerce_to_number

    napi_status napi_coerce_to_number(napi_env env,napi_value value,napi_value* result)

    對於JavaScript中的ToNumber操做的一個實現

  • napi_coerce_to_object

    napi_status napi_coerce_to_object(napi_env env,napi_value value,napi_value* result)

    對於JavaScript中的ToObject操做的一個實現

  • napi_coerce_to_string

    napi_status napi_coerce_to_string(napi_env env,napi_value value,napi_value* result)

    對於JavaScript中的ToString操做的一個實現

  • napi_typeof

    napi_status napi_typeof(napi_env env, napi_value value, napi_valuetype* result)

    對於JavaScript中的typeof操做的一個實現

  • napi_instanceof

    napi_status napi_instanceof(napi_env env,napi_value object,napi_value constructor,bool* result)

    對於JavaScript中的instanceof操做的一個實現

  • napi_is_array

    napi_status napi_is_array(napi_env env, napi_value value, bool* result)

    對於JavaScript中的isArrat函數的一個實現

  • napi_is_arraybuffer

    napi_status napi_is_arraybuffer(napi_env env, napi_value value, bool* result)

  • napi_is_buffer

    napi_status napi_is_buffer(napi_env env, napi_value value, bool* result)

  • napi_is_error

    napi_status napi_is_error(napi_env env, napi_value value, bool* result)

  • napi_is_typedarray

    napi_status napi_is_typedarray(napi_env env, napi_value value, bool* result)

  • napi_strict_equals

    napi_status napi_strict_equals(napi_env env,napi_value lhs,napi_value rhs,bool* result)

    比較傳入的左值和右值是否嚴格相等

關於JavaScript中的屬性

在JavaScript中,屬性通常爲鍵和值的元組,napi中全部屬性鍵均可以用一下形式表示:

  • 命名:一個簡單的utf8字符串
  • 整數索引:一個unit32_t表示的索引值
  • JavaScript值:在napi中有napi_value表示

官方示例:

好比以下JavaScript代碼:

const obj = {};
obj.myProp = 123;複製代碼

轉化成napi模式變成了這樣:

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_number(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;複製代碼

索引值的demo

const arr = [];
arr[123] = 'hello';複製代碼
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;複製代碼

複雜對象的demo

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

napi的格式爲:

napi_status status = napi_status_generic_failure;

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

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

// Set the properties
napi_property_descriptors descriptors[] = {
  { "foo", fooValue, 0, 0, 0, napi_default, 0 },
  { "bar", barValue, 0, 0, 0, napi_default, 0 }
}
status = napi_define_properties(env,
                                obj,
                                sizeof(descriptors) / sizeof(descriptors[0]),
                                descriptors);
if (status != napi_ok) return status;複製代碼

相關結構體

  • napi_property_attributes
    typedef enum {
    napi_default = 0,
    napi_read_only = 1 << 0,
    napi_dont_enum = 1 << 1,
    napi_dont_delete = 1 << 2,
    napi_static_property = 1 << 10,
    } napi_property_attributes;複製代碼

該結構體是用於控制JavaScript對象上設置的屬性的行爲的標誌的,每一個屬性的示例參見官方傳送門

  • napi_property_descriptor
typedef struct {
  const char* utf8name;

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

  napi_property_attributes attributes;
  void* data;
} napi_property_descriptor;複製代碼

該結構體用來描述複雜對象具體的屬性,每一個參數的含義參見官方 傳送門

相關函數

  • napi_get_property_names

    napi_status napi_get_property_names(napi_env env,napi_value object,napi_value* result);

    至關於es6中的keys函數

  • napi_set_property

    napi_status napi_set_property(napi_env env,napi_value object,napi_value key,napi_value value);

    爲對象的某個屬性賦值

  • napi_get_property

    napi_status napi_get_property(napi_env env,napi_value object,napi_value key,napi_value* result);

    獲取對象某個屬性的值

  • napi_has_property

    napi_status napi_has_property(napi_env env,napi_value object,napi_value key,bool* result);

    檢測該對象是否存在對應的鍵

  • napi_set_named_property

    napi_status napi_set_named_property(napi_env env,napi_value object,const char* utf8Name,napi_value value);

    等價於直接調用napi_set_property,不過限定了字符串爲鍵名的狀況

  • napi_get_named_property

    napi_status napi_get_named_property(napi_env env,napi_value object,const char utf8Name,napi_value result);

    等價於調用napi_get_property,限定於字符串爲鍵名的狀況

  • napi_has_named_property

    napi_status napi_has_named_property(napi_env env,napi_value object,const char utf8Name,bool result);

    等價於調用napi_has_property,限定於字符串鍵名狀況

  • napi_set_element

    napi_status napi_set_element(napi_env env,napi_value object,uint32_t index,napi_value value);

    爲一個對象設置索引鍵屬性

  • napi_get_element

    napi_status napi_get_element(napi_env env,napi_value object,uint32_t index,napi_value* result);

    獲取一個對象的索引屬性

  • napi_has_element

    napi_status napi_has_element(napi_env env,napi_value object,uint32_t index,bool* result);

    查詢函數是否包含某個索引複製代碼
  • napi_define_properties

    napi_status napi_define_properties(napi_env env,napi_value object,size_t property_count,const napi_property_descriptor* properties);

這個函數用於高效的建立複雜對象,傳入napi_property_descriptor數組,用於建立複雜對象

JavaScript函數相關

Napi提供了一些列的api,來容許JavaScript調用本機代碼,使用napi_callback類型表示回調函數。這類api容許回調函數進行一下操做:

  • 獲取有關調用回調的上下文信息
  • 獲取傳入回調的參數
  • 從回調中返回一個napi_value

另外,napi還提供了一組容許本地代碼調用JavaScript函數的函數,能夠調用像常規JavaScript函數或做爲構造函數的函數

  • napi_call_function

    napi_status napi_call_function(napi_env env,napi_value recv,napi_value func,int argc,const napi_value argv,napi_value result)

    該函數用於調用js函數,好比如下示例,即是從全局對象中獲取了全局js函數,並調用。

假設全局存在如下函數:

function AddTwo(num) {
  return num + 2;
}複製代碼

而後在下面的代碼中調用:

// 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_number(env, 1337, &arg);
if (status != napi_ok) return;

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

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

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

    napi_status napi_create_function(napi_env env,const char utf8name,napi_callback cb,void data,napi_value* result);

    該函數用於建立一個js中能夠調用的函數,示例以下:

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

void Init(napi_env env, napi_value exports, napi_value module, void* priv) {
  napi_status status;

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

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

NAPI_MODULE(addon, Init)複製代碼
  • napi_get_cb_info

    napi_status napi_get_cb_info(napi_env env,napi_callback_info cbinfo,size_t argc,napi_value argv,napi_value thisArg,void* data)

    該函數用於在回調函數中從給定的回調信息中檢索有關調用的詳細信息

  • napi_is_construct_call

    napi_status napi_is_construct_call(napi_env env,napi_callback_info cbinfo,bool* result)

    該函數用於檢測當前回調是否由構造器調用

  • napi_new_instance

    napi_status napi_new_instance(napi_env env,napi_value cons,size_t argc,napi_value argv,napi_value result)

    該函數用於使用給定的napi_value來實例化一個新的JavaScript值,該值表明該對象的構造函數。示例以下:

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

const arg = 'hello';
const value = new MyObject(arg);複製代碼

在napi中使用該構造函數大體就是這樣:

// 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", -1, &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_make_callback

    napi_status napi_make_callback(napi_env env,napi_value recv,napi_value func,int argc,const napi_value argv,napi_value result)

    該方法容許從本機插件調用JavaScript函數對象。 這個API相似於napi_call_function。 可是,當從異步操做返回時(當堆棧中沒有其餘腳本)時,它用於從本機代碼調用回JavaScript

對象包裹

napi提供了一種"包裝"C++類和實例的方法,以便於在JavaScript中調用類構造函數和方法.
napi_define_class api定義了一個具備構造函數、靜態屬性和方法的JavaScript類,以及與c++類對應的實例屬性和方法。當JavaScript調用構造函數時,會使用napi_wrap將一個新的c++實例包裝在一個JavaScript對像中,而後返回包裝對象,當訪問對應的方法或屬性訪問器時,調用相應的napi_callback C++函數。
ps:因爲對象包裹的內容很麻煩,因此並未在本文中探討

  • napi_define_class

    napi_status napi_define_class(napi_env env,

    const char* utf8name,
                         napi_callback constructor,
                         void* data,
                         size_t property_count,
                         const napi_property_descriptor* properties,
                         napi_value* result);複製代碼
  • napi_wrap

    napi_status napi_wrap(napi_env env,

    napi_value js_object,
                 void* native_object,
                 napi_finalize finalize_cb,
                 void* finalize_hint,
                 napi_ref* result);複製代碼
  • napi_unwrap

    napi_status napi_unwrap(napi_env env,napi_value js_object,void** result);

關於異步操做

在napi中實現了一系列函數用於管理異步操做,使用napi_create_async_work和napi_delete_async_work建立/刪除實例。
其中執行回調會完成回調分別是在程序準備執行時以及執行完成時所調用的函數:

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

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

其中 參數data是調用napi_create_async_work時所傳遞的數據。
建立後可使用napi_queue_async_work函數讓異步工做隊列排隊執行

NAPI_EXTERN napi_status napi_queue_async_work(napi_env env,napi_async_work work);

  • napi_create_async_work

    NAPI_EXTERN
    napi_status napi_create_async_work(napi_env env,napi_async_execute_callback execute,napi_async_complete_callback complete,void data,napi_async_work result);

  • napi_delete_async_work

    NAPI_EXTERN napi_status napi_delete_async_work(napi_env env,napi_async_work work);

  • napi_cancel_async_work

    NAPI_EXTERN napi_status napi_cancel_async_work(napi_env env,napi_async_work work);

相關文章
相關標籤/搜索