栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

NAPI笔记

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

NAPI笔记

NAPI使用笔记
  • NAPI简介
    • NAPI是什么
    • NAPI官网链接
  • NAPI基本数据类型
    • 基本数据类型简介
      • napi_status
      • napi_env
      • napi_value
      • napi_async_work
      • ……
    • 类型转换:C++ -> js
    • 类型转换:js -> C++
  • NAPI实现
    • 接口定义
    • 模块注册
    • 入参类型检查
    • 同步回调
    • 异步回调
  • 应用示例
    • 同步接口的使用
    • 异步接口的使用之promise模式
    • 异步接口的使用之callback模式
  • 参考文献

NAPI简介 NAPI是什么

NAPI提供了一套C/C++接口,用于js和C/C++之间的转换调用,起到承上启下的作用。

NAPI官网链接

NAPI官网提供了详细的接口说明以及使用方法,链接如下,
http://nodejs.cn/api/n-api.html(中文)
https://nodejs.org/api/n-api.html (英文)

NAPI基本数据类型 基本数据类型简介 napi_status

NAPI中大多函数的返回值。枚举值,用于表示函数调用的结果。函数调用成功的时候返回napi_ok。

napi_env

表示上下文,一般使用的时候正常传递就行。

napi_value

对所有js的基本值的封装。

napi_async_work

用于管理异步工作线程。一般使用napi_create_async_work/napi_queue_async_work/napi_delete_async_work进行创建/排队/删除异步工作线程。

…… 类型转换:C++ -> js

这里列举几个常见的数据类型,由C++转化成js数据的方法。

napi_env env;
napi_value value;

// int32_t -> number
int32_t int32Data = 1;
napi_create_int32(env, int32Data, &value)

// string
std::string stringData;
napi_create_string_utf8(env, stringData.c_str(), NAPI_AUTO_LENGTH, &value);

// bool -> boolean
bool boolData = false;
napi_get_boolean(env, boolData, &value);

// object: 这里举例的是包含point属性的一个object
napi_create_object(env, &value);
int32_t point = 0;
napi_value npoint;
napi_create_int32(env, point, &npoint);
napi_set_named_property(env, value, "point", npoint);

// vector -> array
std::vector vecDatas;
vecDatas.push_back(1);
napi_create_array(env, &value);
size_t index = 0;
for (auto& vecData : vecDatas) {
    napi_value id;
    napi_create_int32(env, vecData, &id);
    napi_set_element(env, value, index, id);
    index++;
}
类型转换:js -> C++

这里列举几个常见的数据类型,由js转化成C++数据的方法。

napi_env env;
napi_value value;

// string
char outBuffer[1024 + 1] = {0};
size_t outSize = 0;
napi_get_value_string_utf8(env, value, outBuffer, 1024, &outSize);
std::string result = std::string(outBuffer);

// bool
bool result = false;
napi_get_value_bool(env, value, &result);

// number
int32_t result = 0;
napi_get_value_int32(env, args, &result);
NAPI实现

NAPI的实现应先进行模块注册。一般来说,每个js接口都应有一个绑定的C++接口进行底层逻辑的处理,所以模块注册的时候,也需要将对应的js接口和C++接口进行绑定。js接口有同步和异步两种模式,并且,异步模式中也有promise模式和callback模式。下文将对这三种类型的接口进行举例说明。

接口定义

这里列举几个接口示例,下文的NAPI接口实现也是在以下几个接口的基础上实现的。

// js接口
function helloWorld(key: string): string; // 同步调用接口
function helloWorld(key: string, callback: AsyncCallback): void; // 异步调用接口,callback模式
function helloWorld(key: string): Promise; // 异步调用接口,promise模式

// C++接口
static napi_value HelloWorld(napi_env env, napi_callback_info info);
模块注册

模块注册的时候应该将js接口和C++接口进行绑定并暴露出去。

#define DECLARE_NAPI_FUNCTION(name, func)                                         
    {                                                                             
        name, 0, func, 0, 0, 0, napi_default, 0                                   
    }

// 模块初始化函数,用于绑定js和C++对应的接口
static napi_value Init(napi_env env, napi_value exports)
{
    napi_property_descriptor descriptor[] = {
        DECLARE_NAPI_FUNCTION("helloWorld", HelloWorld),
    };

    napi_define_properties(env, exports, sizeof(descriptor) / sizeof(descriptor[0]), descriptor);
    return exports;
}

NAPI_MODULE(hello, Init) // 注册hello模块
入参类型检查

当napi接口被调用时,最好对入参进行类型检查,以保障后续的逻辑处理。以下使用napi_typeof接口进行参数类型的判断,详细的接口参数说明可见NAPI官网。

bool CheckNumber(napi_env env, napi_value value)
	napi_valuetype type;
	napi_status status = napi_typeof(env, value, &type);
	if (status != napi_ok) {
	    return false;
	}

	if (type != napi_number) {
	    return false;
	}
	return true;
}

// napi_valuetype的枚举值如下
typedef enum {
  napi_undefined,
  napi_null,
  napi_boolean,
  napi_number,
  napi_string,
  napi_symbol,
  napi_object,
  napi_function,
  napi_external,
  napi_bigint,
} napi_valuetype;
同步回调

同步调用的接口,调用后会阻塞住js线程,直至接口的结果返回,一般逻辑处理简单且不耗时的接口会选择同步处理。

function helloWorld(key: string): string; // js接口
static napi_value HelloWorld(napi_env env, napi_callback_info info); // C++接口

NAPI的函数实现如下

static napi_value HelloWorld(napi_env env, napi_callback_info info)
{
    // 获取js的入参数据
    size_t argc = 1; // 参数个数
    napi_value argv = nullptr; // 参数的值
    napi_value thisVar = nullptr; // js对象的this指针
    void* data = nullptr; // 回调数据指针
    napi_get_cb_info(env, info, &argc, &argv, &thisVar, &data)
    NAPI_ASSERT(env, argc == 1, "requires 1 parameter");

    // 判断入参的类型是否正确
	napi_valuetype type = napi_undefined;
	napi_typeof(env, argv, &type);
    NAPI_ASSERT(env, type == napi_string, "the type of arg is not string");

    // 解析入参
    char outBuffer[1024 + 1] = {0};
    size_t outSize = 0;
    napi_get_value_string_utf8(env, argv, outBuffer, 1024, &outSize);
    std::string key = std::string(outBuffer);

    // 处理入参并向js返回结果
    napi_value result = nullptr;
    std::string value = key + "HelloWorld";
    napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
    return result;
}
异步回调

由于js的单线程处理方式,为提高效率,使用异步回调的接口较多。为方便,以下NAPI的实现将promise模式和callback模式放到一起处理,也可分开实现。

// js接口
function helloWorld(key: string, callback: AsyncCallback): void; // 异步调用接口,callback模式
function helloWorld(key: string): Promise; // 异步调用接口,promise模式

// C++接口
static napi_value HelloWorld(napi_env env, napi_callback_info info);

NAPI的函数实现如下

struct HelloWorldCallBack {
    napi_async_work work;
    napi_ref callbackRef = nullptr;
    napi_deferred deferred;
    std::string key = "";
    std::string value = "";
    bool ret = false;
}

static napi_value HelloWorld(napi_env env, napi_callback_info info)
{
    // 获取js的入参数据
    size_t argc = 2; // 参数个数
    napi_value argv[2] = {0}; // 参数的值
    napi_value thisVar = nullptr; // js对象的this指针
    void* data = nullptr; // 回调数据指针
    napi_get_cb_info(env, info, &argc, argv, &thisVar, &data)
    NAPI_ASSERT(env, ((argc >= 1) && (argc <= 2)), "requires 1 parameter");

    // 判断入参的类型是否正确
	napi_valuetype type = napi_undefined;
	napi_typeof(env, argv[0], &type);
    NAPI_ASSERT(env, type == napi_string, "the type of argv[0] is not string");
    if (argc == 2) {
        napi_typeof(env, argv[1], &type);
        NAPI_ASSERT(env, type == napi_function, "the type of argv[1] is not function");
    }

    HelloWorldCallBack* callback = new HelloWorldCallBack();

    // 解析入参key
    char outBuffer[1024 + 1] = {0};
    size_t outSize = 0;
    napi_get_value_string_utf8(env, argv[0], outBuffer, 1024, &outSize);
    callback->key = std::string(outBuffer);

    // 解析入参callback
    if (argc == 2) {
        napi_create_reference(env, argv[1], 1, &callback->callbackRef);
    }

    napi_value promise = nullptr;
	// callback ref为空,说明是promise模式,反之是callback模式
    if (!callback->callbackRef_) {
        napi_create_promise(env, &callback->deferred, &promise);
    } else {
        napi_get_undefined(env, &promise);
    }

    napi_value resource = nullptr;
    napi_create_string_utf8(env, "HelloWorld", NAPI_AUTO_LENGTH, &resource);
	// 创建异步工作
    napi_create_async_work(env, nullptr, resource,
        [](napi_env env, void* data) {
            HelloWorldCallBack* callback = static_cast(data);
            if (callback->key == "") {
                callback->ret = false;
            } else {
                callback->ret = true;
                callback->value = callback->key + "HelloWorld";
            }
        },
        [](napi_env env, napi_status status, void* data) {
            HelloWorldCallBack* callback = static_cast(data);
            napi_value result[2] = {0};

            if (callback->ret) {
                napi_create_string_utf8(env, callback->value.c_str(), NAPI_AUTO_LENGTH, &result[1]);
            } else {
                napi_get_undefined(env, &result[1]);
            }

            if (callback->callbackRef) {
                // callback模式
                // 根据execute函数的结果进行err code的赋值
                napi_value errCode = nullptr;
                napi_create_int32(env, callback->ret ? 0 : 1, &errCode);
                napi_create_object(env, &result[0]);
                napi_set_named_property(env, result[0], "code", errCode);

				// 调用对应的js的callback函数
                napi_value callback = nullptr;
                napi_get_reference_value(env, callback->callbackRef, &callback);
                napi_call_function(env, nullptr, callback, sizeof(result) / sizeof(result[0]), result, nullptr);
                napi_delete_reference(env, callback->callbackRef);
            } else {
                // promise模式
                if (callback->ret) {
                    napi_resolve_deferred(env, callback->deferred, result[1]);
                } else {
                    napi_reject_deferred(env, callback->deferred, result[1]);
                }
            }
            napi_delete_async_work(env, callback->work); // 异步任务完成之后删除任务
            delete callback;
        }, (void*)callback, &callback->work);
    napi_queue_async_work(env, callback->work); //异步任务入队列,排队执行
    return promise;
}
应用示例

以下对上文中提出的js接口进行应用举例。

同步接口的使用
var value = HelloWorld('key1'); 
异步接口的使用之promise模式
HelloWorld('key2').then((value) => {
    console.log('value is ' + value);
}).catch((error) => {
    console.log('error: ' + error);
});
异步接口的使用之callback模式
HelloWorld('key2', (err, value) => {
    console.log('err.code: ' + err.code + " value: " + value);
});
参考文献

https://ost.51cto.com/posts/8390

暑期编程PK赛 得CSDN机械键盘等精美礼品!
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1016170.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号