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

相关文章
相关标签/搜索