三方库移植之NAPI开发[4]异步调用:CallbackPromise

2024-04-13 02:28

本文主要是介绍三方库移植之NAPI开发[4]异步调用:CallbackPromise,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

写在开头

  • 本文在 三方库移植之NAPI开发[1]—Hello OpenHarmony NAPI 的基础上修改hellonapi.cpp、index.ets,接着学习NAPI异步模型的Promise、Callback方式。
  • 本文共有三个示例,分别是Callback 异步接口示例、Promise 异步接口示例、规范异步接口示例。在本文末尾的资源中提供了这三个示例的源代码,读者可以下载在开发板上运行。
  • 开发基于最新的OpenHarmony3.2Beta3版本及API9,标准系统开发板为润和软件DAYU200。

NAPI异步方式实现原理

  • 同步方式和异步方式
    同步方式,所有的代码处理都在原生方法(主线程)中完成。
    异步方式,所有的代码处理在多个线程中完成。

  • 实现NAPI异步方法的步骤
    1)立即返回一个临时结果给js调用者
    2)另起线程完成异步业务逻辑的执行
    3)通过callback或promise返回真正的结果

  • 异步工作项工作时序图

  • 原生方法被调用时,原生方法完成数据接收数据类型转换存入上下文数据,之后创建异步工作项
  • 异步工作项会加入调度队列,由异步工作线程池统一调度,原生方法返回空值(Callback方式)或返回Promise对象(Promise方式)。
  • 异步方式依赖NAPI框架提供的napi_create_async_work()函数创建异步工作项
    napi_create_async_work()在foundation/arkui/napi/native_engine/native_node_api.cpp第71行
NAPI_EXTERN 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: 传入接口调用者的环境,包含js引擎等,由框架提供,默认情况下直接传入即可。
[in] async_resource: 可选项,关联async_hooks。
[in] async_resource_name: 异步资源标识符,主要用于async_hooks API暴露断言诊断信息。
[in] execute: 执行业务逻辑计算函数,由worker线程池调度执行。在该函数中执行IO、CPU密集型任务,不阻塞主线程。
[in] complete: execute参数指定的函数执行完成或取消后,触发执行该函数。此函数在EventLoop线程中执行。
[in] data: 用户提供的上下文数据,用于传递数据。
[out] result: napi_async_work*指针,用于返回当前此处函数调用创建的异步工作项。 返回值:返回napi_ok表示转换成功,其他值失败。

napi_create_async_work里有两个回调:

  • execute
    • execute函数用于执行工作项的业务逻辑,异步工作项被调度后,该函数从上下文数据中获取输入数据,在worker线程中完成业务逻辑计算(不阻塞主线程)并将结果写入上下文数据。
    • 因为execute函数不在JS线程中,所以不允许execute函数调用napi的接口。业务逻辑的返回值可以返回到complete回调中处理。
  • complete
    • 业务逻辑处理execute函数执行完成或被取消后,触发EventLoop执行complete函数,complete函数从上下文数据中获取结果,转换为JS类型,调用JS回调函数通过Promise resolve()返回结果。
    • 可以调用napi的接口,将execute中的返回值封装成JS对象返回。此回调在JS线程中执行。
  • 管理简单的异步操作的方法还有这些
    • napi_delete_async_work(napi_env env, napi_async_work work)
      删除异步工作线程
    • napi_queue_async_work(napi_env env, napi_async_work work)
      将刚创建的异步工作项加到队列(排队),由底层去调度执行
    • napi_cancel_async_work(napi_env env, napi_async_work work)
      取消异步工作项

NAPI支持异步模型

  • OpenHarmony标准系统异步接口实现支持Promise方式和Callback方式。NAPI支持异步模型,提供了Promise、Callback方式。
  • 标准系统异步接口实现规范要求,若引擎开启Promise特性支持,则异步方法必须同时支持Callback方式和Promise方式。
    • 由应用开发者决定使用哪种方式,通过是否传递Callback函数区分异步方法是Callback方式还是Promise方式
    • 不传递Callback即为Promise方式(方法执行结果为Promise实例对象),否则为Callback方式
  • Promise、Callback 异步模型都是 OHOS 标准异步模型。
  • Callback异步模型
    • 用户在调用接口的时候,接口实现将异步执行任务
    • 任务执行结果以参数的形式提供给用户注册的回调函数,这些参数的第一个是 Error 或 undefined 类型,分别表示执行出错与正常。
  • Promise异步模型
    • 对象的状态不受外界影响;
    • 一旦状态改变了就不会再变,也就是说任何时候Promise都只有一种状态。
  • ES6原生提供了Promise对象,Promise是异步编程的一种解决方案,可以替代传统的解决方案回调函数和事件;
    • promise对象是一个异步操作的结果,提供了一些API使得异步执行可以按照同步的流表示出来,避免了层层嵌套的回调函数,保证了回调是以异步的方式进行调用的;
    • 用户在调用这些接口的时候,接口实现将异步执行任务,同时返回一个 Promise 对象,其代表异步操作的结果;
    • 在返回的结果的个数超过一个时,其以对象属性的形式返回。
  • ES6:全称ECMAScript 6.0。ECMAScript 是JavaScript语言的国际标准,JavaScript是ECMAScript的实现。

Callback 异步接口

Callback 异步接口示例代码

hellonapi.cpp文件

#include <string.h>
#include <stdio.h>
#include "napi/native_node_api.h"
#include "napi/native_api.h"// 用户提供的上下文数据,在原生方法(初始化数据)、executeCB、completeCB之间传递数据
struct AddonData {napi_async_work asyncWork = nullptr;napi_deferred deferred = nullptr;napi_ref callback = nullptr;double args[2] = {0};double result = 0;
};// 业务逻辑处理函数,由worker线程池调度执行。
static void addExecuteCB(napi_env env, void *data) {AddonData *addonData = (AddonData *)data;// 执行复杂计算,不阻塞主线程。此处用一个加法简单示意。addonData->result = addonData->args[0] + addonData->args[1];
}// 业务逻辑处理完成回调函数,在业务逻辑处理函数执行完成或取消后触发,由EventLoop线程中执行。
static void addCallbackCompleteCB(napi_env env, napi_status status, void *data) {AddonData *addonData = (AddonData *)data;napi_value callback = nullptr;napi_get_reference_value(env, addonData->callback, &callback);napi_value undefined = nullptr;napi_get_undefined(env, &undefined);napi_value result = nullptr;napi_create_double(env, addonData->result, &result);napi_value callbackResult = nullptr;// 执行回调函数napi_call_function(env, undefined, callback, 1, &result, &callbackResult);// 删除napi_ref对象if (addonData->callback != nullptr) {napi_delete_reference(env, addonData->callback);}// 删除异步工作项napi_delete_async_work(env, addonData->asyncWork);delete addonData;
}static napi_value addCallback(napi_env env, napi_callback_info info) {// 获取3个参数,值的类型是js类型(napi_value)size_t argc = 3;napi_value args[3];napi_value thisArg = nullptr;NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisArg, nullptr));// 获取并判断js参数类型napi_valuetype valuetype0;NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0));napi_valuetype valuetype1;NAPI_CALL(env, napi_typeof(env, args[1], &valuetype1));if (valuetype0 != napi_number || valuetype1 != napi_number) {napi_throw_type_error(env, nullptr, "Wrong arguments. 2 numbers expected.");return NULL;}napi_valuetype valuetype2;NAPI_CALL(env, napi_typeof(env, args[2], &valuetype2));if (valuetype2 != napi_function) {napi_throw_type_error(env, nullptr, "Callback function expected.");return NULL;}// 异步工作项上下文用户数据,传递到异步工作项的execute、complete中传递数据auto addonData = new AddonData{.asyncWork = nullptr,};// 将接收到的参数传入用户自定义上下文数据NAPI_CALL(env, napi_get_value_double(env, args[0], &addonData->args[0]));NAPI_CALL(env, napi_get_value_double(env, args[1], &addonData->args[1]));NAPI_CALL(env, napi_create_reference(env, args[2], 1, &addonData->callback));// 创建async work,创建成功后通过最后一个参数接收async work的handlenapi_value resourceName = nullptr;napi_create_string_utf8(env, "addCallback", NAPI_AUTO_LENGTH, &resourceName);napi_create_async_work(env, nullptr, resourceName, addExecuteCB, addCallbackCompleteCB, (void *)addonData,&addonData->asyncWork);// 将刚创建的async work加到队列,由底层去调度执行napi_queue_async_work(env, addonData->asyncWork);// 原生方法返回空对象napi_value result = 0;NAPI_CALL(env, napi_get_null(env, &result));return result;
}// napi_addon_register_func
static napi_value registerFunc(napi_env env, napi_value exports) {static napi_property_descriptor desc[] = {DECLARE_NAPI_FUNCTION("addCallback", addCallback),};NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));return exports;
}// 定义napi_module,指定当前NAPI模块对应的模块名
//以及模块注册对外接口的处理函数,具体扩展的接口在该函数中声明
// nm_modname: 模块名称,对应eTS代码为import nm_modname from '@ohos.ohos_shared_library_name'
//示例对应eTS代码为:import hellonapi from '@ohos.hellonapi'
static napi_module hellonapiModule = {.nm_version = 1,.nm_flags = 0,.nm_filename = nullptr,.nm_register_func = registerFunc, // 模块对外接口注册函数.nm_modname = "hellonapi",  // 自定义模块名.nm_priv = ((void*)0),.reserved = { 0 },
};// 模块定义好后,调用NAPI提供的模块注册函数napi_module_register(napi_module* mod)函数注册到系统中。
// register module,设备启动时自动调用此constructor函数,把模块定义的模块注册到系统中
extern "C" __attribute__((constructor)) void hellonapiModuleRegister()
{napi_module_register(&hellonapiModule);
}

index.ets

import prompt from '@system.prompt';
import hellonapi from '@ohos.hellonapi'@Entry
@Component
struct TestAdd {build() {Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {Button("hellonapi.addCallback(x, y, callback)").margin(10).fontSize(20).onClick(() => {let num1 = 123, num2 = 456hellonapi.addCallback(num1, num2, (result) => {prompt.showToast({ message: `hellonapi.addCallback(${num1}, ${num2}) = ${result}` })})})}.width('100%').height('100%')}
}

@ohos.hellonapi.d.ts

declare namespace hellonapi {function addCallback(num1: number, num2: number, callback:(result: number) => void): void;/*** ** @since 9* @syscap SystemCapability.Ability.AbilityRuntime.AbilityCore*/}
export default hellonapi;

主线程:获取JS传入参数

获取JS传入参数在异步工作项工作时序图中位置,在图中用红框标记如下

  // 获取并判断js参数类型napi_valuetype valuetype0;NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0));
// 使用napi_typeof接口进行参数类型的判断napi_valuetype valuetype1;NAPI_CALL(env, napi_typeof(env, args[1], &valuetype1));// 如果valuetype2调用的不是数据类型,则抛出异常“Wrong arguments. 2 numbers expected.”if (valuetype0 != napi_number || valuetype1 != napi_number) {napi_throw_type_error(env, nullptr, "Wrong arguments. 2 numbers expected.");return NULL;}napi_valuetype valuetype2;NAPI_CALL(env, napi_typeof(env, args[2], &valuetype2));// 如果valuetype2调用的不是function类型(callback),则抛出异常“Callback function expected”if (valuetype2 != napi_function) {napi_throw_type_error(env, nullptr, "Callback function expected.");return NULL;}
  • 使用napi_typeof接口进行参数类型的判断
  • NAPI_CALL()是用来调用NAPI中的API的。

主线程:初始化上下文数据

初始化上下文数据在异步工作项工作时序图中位置,在图中用红框标记如下

  • 异步方法需要在不同线程中传递各种业务数据上下文数据),就需要定义一个结构体保存这些被传递的信息。用于在主线程方法、Work线程、EventLoop线程之间传递数据。

struct 结构体名(也就是可选标记名){ 成员变量;};//使用分号;表示定义结束。

  • 本示例定义的上下文数据包含:异步工作项对象回调函数2个参数(加数、被加数)、业务逻辑处理结果等4个属性。
// 定义异步工作项上下文数据
// 用户提供的上下文数据,用于在主线程方法、Work线程、EventLoop线程之间传递数据。
struct AddonData {napi_async_work asyncWork = nullptr;   //异步工作对象asyncWorknapi_ref callback = nullptr;           //回调函数callbackdouble args[2] = {0};                  //2个输入参数double result = 0;                     //业务逻辑处理结果result(返回值)
};
  • OpenHarmony的NAPI框架将ECMAScript标准中定义的Boolean、Null、Undefined、Number、BigInt、String、Symbol和Object八种数据类型Function类型,都已统一封装为napi_value类型,故可如获取数据类型的参数一样获取Function类型的参数。

Function是JavaScript提供的一种引用类型,通过Function类型创建Function对象。
在JavaScript中,函数也是以对象的形式存在的,每个函数都是一个Function对象。

  • 定义好结构体后,接着我们将接收到的3个参数(加数被加数回调函数)转换存入上下文数据完成初始化上下文数据
    • number类型的(加数被加数)转换为double直接存入。
    • Function类型的参数(回调函数)怎么处理?不能直接存入napi_value类型。
      • 因为牵涉到NAPI对象生命周期管理问题。napi_value类型引用对象的生命周期在原生方法退出后结束,后面在work线程无法获取其值。
      • NAPI提供了一种生命期限长于原生方法的对象引用类型—— napi_ref,所以调用napi_create_reference()函数将接收到的napi_value类型的回调函数参数callback转换为napi_ref类型。napi_create_reference()函数定义如下:
NAPI_EXTERN napi_status napi_create_reference(napi_env env,napi_value value,uint32_t initial_refcount,napi_ref* result);

参数说明:
[in] env: 传入接口调用者的环境,包含js引擎等,由框架提供,默认情况下直接传入即可。
[in] value: 需要创建一个引用的napi_value对象
[in] initial_refcount: 初始化引用次数。
[out] result: 指针,指向新创建的napi_ref对象。 返回值:返回napi_ok表示转换成功,其他值失败。

  • napi_ref引用对象在原生方法退出后不自动回收,由用户管理napi_ref类型对象的生命周期。
    • 用户管理napi_ref类型对象的生命周期的方法有
      • napi_create_reference() : 将napi_value包装成napi_ref引用对象
      • napi_get_reference_value() : 从napi_ref引用对象中取得napi_value
      • napi_delete_reference() :删除napi_ref引用对象
    • 通过napi_create_reference()方法将napi_value创建一个napi_ref,这个napi_ref是可以跨作用域传递的,然后在需要用到的地方用napi_get_reference_value()方法将napi_ref还原为napi_value,用完后再用napi_delete_reference()方法删除引用对象以便释放相关内存资源。
static napi_value addAsyncCallback(napi_env env, napi_callback_info info) {
// NAPI定义API方法时的接收参数为(napi_env, napi_callback_info)
// 其中napi_callback_info为上下文的信息。size_t argc = 3;   // 有3个参数(`加数`、`被加数`、`回调函数`)到上下文中napi_value args[3];napi_value thisArg = nullptr;NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisArg, nullptr));
// NAPI提供了napi_get_cb_info()方法可从napi_callback_info中获取参数列表、this及其他数据。...// 异步工作项上下文用户数据,传递到异步工作项的execute、complete中传递数据// 创建结构体addonData用于保存各种需要在异步线程中传递的数据信息auto addonData = new AddonData{.asyncWork = nullptr,};// 将接收到的3个参数(`加数`、`被加数`、`回调函数`)传入用户自定义上下文数据NAPI_CALL(env, napi_get_value_double(env, args[0], &addonData->args[0]));// NAPI_CALL()是用来调用NAPI中的API的// NAPI提供napi_get_value_double方法将JS类型double值转换为C++类型的double值NAPI_CALL(env, napi_get_value_double(env, args[1], &addonData->args[1]));  NAPI_CALL(env, napi_create_reference(env, args[2], 1, &addonData->callback));//调用napi_create_reference()函数将接收到的napi_value类型的回调函数callback转换为napi_ref类型,将napi_value包装成napi_ref引用对象。并保存到asyncContext上下文数据中,以便后续在C++异步线程中能够回调该js fuction类型。//参数解释如下// env: 传入接口调用者的环境,包含js引擎等,由框架提供,默认情况下直接传入即可// args[2]: 引用的napi_value对象 (加数和被加数)// 1:初始化引用1次// &addonData->callback: 指向新创建的napi_ref 对象(callback) ...
}
  • NAPI_CALL()是用来调用NAPI中的API的。

主线程:创建异步工作项

创建异步工作项在异步工作项工作时序图中位置,在图中用红框标记如下

  • 第一步:在创建异步工作项前,分别声明addExecuteCB、addAsyncCompleteCB这2个函数,分别用作于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)函数的execute、complete参数。
  • 第二步:利用NAPI框架提供的napi_create_async_work()函数创建异步工作项,将addExecuteCB、addAsyncCompleteCB这2个函数存入上下文数据的asyncWork属性
// 业务逻辑处理函数,由异步work线程池统一调度
static void addExecuteCB(napi_env env, void *data) {
}// 业务逻辑处理完成回调函数,在业务逻辑处理函数执行完成或取消后触发。
static void addAsyncCompleteCB(napi_env env, napi_status status, void *data) {
}static napi_value addAsyncCallback(napi_env env, napi_callback_info info) {...// 创建async work,创建成功后通过最后一个参数接收async work的handlenapi_value resourceName = nullptr;// 根据UTF8编码格式的 C/C++字符串 创建一个 JS字符串对象.
// 传入的参数是Javascript值类型,被NAPI框架封装成统一的唯一类型——napi_value类型,为了能够进行计算,我们需要获取其对应在C/C++中的类型的值。将C/C++ utf8类型的值转为node_value类型,返回给JS代码napi_create_string_utf8(env, "addCallback", NAPI_AUTO_LENGTH, &resourceName); //参数说明如下//env: 传入接口调用者的环境,包含js引擎等,由框架提供,默认情况下直接传入即可//addCallback:定义的上下文信息中的addCallback对象//NAPI_AUTO_LENGTH:字符长度//resourceName:创建的napi_value对象// 异步方式依赖NAPI框架提供的napi_create_async_work()函数创建异步工作项napi_create_async_work(env, nullptr, resourceName,   addExecuteCB  ,  addCallbackCompleteCB  ,   (void *)addonData,&addonData->asyncWork);//参数说明如下//env: 传入接口调用者的环境,包含js引擎等,由框架提供,默认情况下直接传入即可。//第二个参数是nullptr//resourceName: 定义的上下文信息中的addCallback对象(异步资源标识符),主要用于async_hooks API暴露断言诊断信息。//addExecuteCB:执行业务逻辑计算函数,由worker线程池调度执行。在该函数中执行IO、CPU密集型任务,不阻塞主线程。//addCallbackCompleteCB: execute参数指定的函数执行完成或取消后,触发执行该函数。此函数在EventLoop线程中执行。//(void *)addonData: 用户提供的上下文数据,用于传递数据。//&addonData->asyncWork: 用于返回当前此处函数调用创建的异步工作项。 返回值:返回napi_ok表示转换成功,其他值失败。...
}

主线程:异步工作项加入队列,等待调度

异步工作项加入队列,等待调度在异步工作项工作时序图中位置,在图中用红框标记如下

static napi_value addAsyncCallback(napi_env env, napi_callback_info info) {...// 将刚创建的异步工作项(async work)加到队列,由work thread调度执行napi_queue_async_work(env, addonData->asyncWork);// 其中asyncWork是上下文数据中创建的异步工作对象,用于管理异步工作线程。...
}

主线程:原生方法返回临时返回值

  • 调用napi_queue_async_work()将异步工作项加入调度队列,由异步work线程池统一调度,原生方法返回空值退出。

  • 用户在调用接口的时候,接口实现将异步执行任务,任务执行结果以参数的形式提供给用户注册的回调函数(callback),这些参数的第一个是 Error 或 undefined 类型,分别表示执行出错与正常。

static napi_value addAsyncCallback(napi_env env, napi_callback_info info) {...// 为异步方法创建临时返回值,在此处原生方法临时返回值是一个空对象napi_value result = 0;// callback接口返回参数为void,用napi_get_null()构造一个空对象的返回值即可。NAPI_CALL(env, napi_get_null(env, &result));return result;
}

work线程:执行业务逻辑、把计算结果写入上下文数据

执行业务逻辑把计算结果写入上下文数据在异步工作项工作时序图中位置,在图中用红框标记如下

创建异步工作项前,声明了addExecuteCB这个函数,用作于napi_create_async_work()函数的execute参数。

  • execute函数在异步工作项被调度后在work线程中执行

    • 不阻塞主线程(不阻塞UI界面)
    • 可执行IO、CPU密集型等任务。
  • 执行业务逻辑:业务逻辑计算是一个简单的加法,并把计算结果存入上下文数据的result属性

  • 把计算结果写入上下文数据:把execute函数的结构体指向上下文数据中结构体。

// 业务逻辑处理函数,由worker线程池调度执行。
static void addExecuteCB(napi_env env, void *data) {// 把计算结果写入上下文数据,把addonData指向AddonDataAddonData *addonData = (AddonData *)data;// 执行业务逻辑,// 不阻塞主线程。此处是一个加法addonData->result = addonData->args[0] + addonData->args[1];
}

EventLoop线程:把上下文中的结果转为JS类型、调用JS回调函数

把上下文中的结果转为JS类型调用JS回调函数在异步工作项工作时序图中位置,在图中用红框标记如下

  • 创建异步工作项前,声明addAsyncCompleteCB这个函数,用作于napi_create_async_work()函数的complete参数。
    • 第一步:addAsyncCompleteCB从接收到的上下文数据中获取结果,调用napi_call_function()方法执行JS回调函数返回数据给JS。
    • 第二步: 释放(删除)过程中创建的napi_ref引用对象、异步工作项等对象。
// 业务逻辑处理完成回调函数,在业务逻辑处理函数执行完成或取消后触发,由EventLoop线程中执行。
static void addCallbackCompleteCB(napi_env env, napi_status status, void *data) {
//所有的接口调用返回一个napi_status类型的状态码,用来表明接口调用成功或者失败AddonData *addonData = (AddonData *)data;napi_value callback = nullptr;//从napi_ref引用对象中取得napi_valuenapi_get_reference_value(env, addonData->callback, &callback);napi_value undefined = nullptr;napi_get_undefined(env, &undefined);napi_value result = nullptr;napi_create_double(env, addonData->result, &result);napi_value callbackResult = nullptr;// 执行回调函数napi_call_function(env, undefined, callback, 1, &result, &callbackResult);// 删除napi_ref对象if (addonData->callback != nullptr) {napi_delete_reference(env, addonData->callback);}// 删除异步工作项napi_delete_async_work(env, addonData->asyncWork);delete addonData;
}
  • NAPI框架提供了napi_call_function()函数供扩展Natvie代码(C/C++代码)调用JS函数,用于执行回调函数等场景。函数定义如下:

// Methods to work with Functions
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: 传入接口调用者的环境,包含js引擎等,由框架提供,默认情况下直接传入即可。
[in] recv: 传给被调用的this对象。
[in] func: 被调用的函数.
[in] argc: 函数参数个数(对应函数数组的长度)。
[in] argv: 函数参数数组.
[out] result: func函数执行的返回值。 返回值:返回napi_ok表示转换成功,其他值失败。

  • 因对象生命周期管理问题,上下文数据的callback属性的类型为napi_ref,需要调用napi_get_reference_value()函数获取其指向的napi_value对象值才调用napi_call_function()函数。 napi_get_reference_value函数定义:

// Attempts to get a referenced value. If the reference is weak,
// the value might no longer be available, in that case the call
// is still successful but the result is nullptr.
NAPI_EXTERN napi_status napi_get_reference_value(napi_env env, napi_ref ref,  napi_value* result)

参数说明:
[in] env: 传入接口调用者的环境,包含js引擎等,由框架提供,默认情况下直接传入即可。
[in] ref: napi_ref对象
[out] result: napi_ref引用的napi_value对象。 返回值:返回napi_ok表示转换成功,其他值失败。

  • 执行回调函数是为了在异步操作之后调用JS函数

  • napi_delete_reference()用于删除上下文数据中定义的napi_ref对象callback。napi_ref引用对象在原生方法退出后不自动回收,由用户管理napi_ref类型对象的生命周期。

  • napi_delete_async_work()用于删除异步工作线程,在异步调用的结尾释放async_work和相关业务数据的内存

Callback异步接口总结

以下图片为个人总结,可以在文末下载清晰的图片,下载之后推荐到[diagrams]。

Promise异步接口

Promise异步接口示例代码

hellonapi.cpp

#include <string.h>
#include<stdio.h>
#include "napi/native_node_api.h"
#include "napi/native_api.h"// 用户提供的上下文数据,在原生方法(初始化数据)、executeCB、completeCB之间传递数据
struct AddonData {napi_async_work asyncWork = nullptr;napi_deferred deferred = nullptr;napi_ref callback = nullptr;double args[2] = {0};double result = 0;};// 业务逻辑处理函数,由worker线程池调度执行。
static void addExecuteCB(napi_env env, void *data) {AddonData *addonData = (AddonData *)data;// 执行复杂计算,不阻塞主线程。此处用一个加法简单示意。addonData->result = addonData->args[0] + addonData->args[1];// addonData->result = addonData->args[0] + addonData[1];
}static void addPromiseCompleteCB(napi_env env, napi_status status, void *data) {AddonData *addonData = (AddonData *)data;napi_value result = nullptr;napi_create_double(env, addonData->result, &result);napi_resolve_deferred(env, addonData->deferred, result);// 删除napi_ref对象if (addonData->callback != nullptr) {napi_delete_reference(env, addonData->callback);}// 删除异步工作项napi_delete_async_work(env, addonData->asyncWork);delete addonData;addonData = nullptr;
}static napi_value addPromise(napi_env env, napi_callback_info info) {// 获取2个参数,值的类型是js类型(napi_value)size_t argc = 2;napi_value args[2];napi_value thisArg = nullptr;NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisArg, nullptr));// 获取并判断js参数类型napi_valuetype valuetype0;NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0));napi_valuetype valuetype1;NAPI_CALL(env, napi_typeof(env, args[1], &valuetype1));if (valuetype0 != napi_number || valuetype1 != napi_number) {napi_throw_type_error(env, nullptr, "Wrong arguments. 2 numbers expected.");return NULL;}// 创建promisenapi_value promise = nullptr;napi_deferred deferred = nullptr;NAPI_CALL(env, napi_create_promise(env, &deferred, &promise));// 异步工作项上下文用户数据,传递到异步工作项的execute、complete之间传递数据auto addonData = new AddonData{.asyncWork = nullptr,.deferred = deferred,};// 将接收到的参数传入NAPI_CALL(env, napi_get_value_double(env, args[0], &addonData->args[0]));NAPI_CALL(env, napi_get_value_double(env, args[1], &addonData->args[1]));// 创建async work,创建成功后通过最后一个参数(addonData->asyncWork)返回async work的handlenapi_value resourceName = nullptr;napi_create_string_utf8(env, "addAsyncCallback", NAPI_AUTO_LENGTH, &resourceName);napi_create_async_work(env, nullptr, resourceName, addExecuteCB, addPromiseCompleteCB, (void *)addonData,&addonData->asyncWork);// 将刚创建的async work加到队列,由底层去调度执行napi_queue_async_work(env, addonData->asyncWork);// 原生方法返回promisereturn promise;}// napi_addon_register_func
//2.指定模块注册对外接口的处理函数,具体扩展的接口在该函数中声明
static napi_value registerFunc(napi_env env, napi_value exports)
{static napi_property_descriptor desc[] = {{ "addPromise", nullptr, addPromise, nullptr, nullptr, nullptr, napi_default, nullptr }};napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);return exports;   
}// 1.先定义napi_module,指定当前NAPI模块对应的模块名
//以及模块注册对外接口的处理函数,具体扩展的接口在该函数中声明
// nm_modname: 模块名称,对应eTS代码为import nm_modname from '@ohos.ohos_shared_library_name'
//示例对应eTS代码为:import hellonapi from '@ohos.hellonapi'
static napi_module hellonapiModule = {.nm_version = 1,.nm_flags = 0,.nm_filename = nullptr,.nm_register_func = registerFunc, // 模块对外接口注册函数.nm_modname = "hellonapi",  // 自定义模块名.nm_priv = ((void*)0),.reserved = { 0 },
};//3.模块定义好后,调用NAPI提供的模块注册函数napi_module_register(napi_module* mod)函数注册到系统中。
// register module,设备启动时自动调用此constructor函数,把模块定义的模块注册到系统中
extern "C" __attribute__((constructor)) void hellonapiModuleRegister()
{napi_module_register(&hellonapiModule);
}

index.ets

import prompt from '@system.prompt';
import hellonapi from '@ohos.hellonapi'@Entry
@Component
struct TestAdd {build() {Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {Button("hellonapi.addPromise(x, y).then(...)").margin(1).fontSize(20).onClick(() => {let num1 = 123, num2 = 456hellonapi.addPromise(num1, num2).then((result) => {prompt.showToast({ message: `hellonapi.addPromise(${num1}, ${num2}) = ${result}` })})})}.width('100%').height('100%')}
}

@ohos.hellonapi.d.ts

declare namespace hellonapi {function addPromise(num1: number, num2: number): Promise<number>;/*** ** @since 9* @syscap SystemCapability.Ability.AbilityRuntime.AbilityCore*/}
export default hellonapi;

创建Promise

  • Promise整体处理流程和Callback方式一样,在此小节只讨论Promise不同于Callback的部分

  • 首先创建Promise,NAPI框架中提供了napi_create_promise()函数用于创建Promise,调用该函数输出2个对象——deferred、promise。

    • promise用于原生方法返回,deferred传入异步工作项的上下文数据。complete函数中,应用napi_resolve_deferred()函数 或 napi_reject_deferred() 函数返回数据。

函数定义如下:

napi_status napi_create_promise(napi_env env,napi_deferred* deferred,napi_value* promise);

参数说明:

[in] env: 传入接口调用者的环境,包含js引擎等,由框架提供,默认情况下直接传入即可。
[out] deferred: 返回接收刚创建的deferred对象,关联Promise对象,后面使用napi_resolve_deferred() 或 napi_reject_deferred() 返回数据。
[out] promise: 关联上面deferred对象的JS Promise对象 返回值:返回napi_ok表示转换成功,其他值失败。

static napi_value addPromise(napi_env env, napi_callback_info info) {// 创建promisenapi_value promise = nullptr;napi_deferred deferred = nullptr;// 创建promise对象。promise用于返回promise对象给js调用者NAPI_CALL(env, napi_create_promise(env, &deferred, &promise));...// 返回promisereturn promise;
}

初始化上下文数据

  • 定义一个上下文数据结构,用于保存和传递数据。Promise方式加上deferred属性。
// 用户提供的上下文数据,在原生方法(初始化数据)、executeCB、completeCB之间传递数据
struct AddonData {...napi_deferred deferred = nullptr;double args[2] = {0};...
};static napi_value addPromise(napi_env env, napi_callback_info info) {// 获取2个参数,值的类型是js类型(napi_value)size_t argc = 2;napi_value args[2];napi_value thisArg = nullptr;NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisArg, nullptr));...// 创建promisenapi_value promise = nullptr;napi_deferred deferred = nullptr;NAPI_CALL(env, napi_create_promise(env, &deferred, &promise));...// 将接收到的参数传入NAPI_CALL(env, napi_get_value_double(env, args[0], &addonData->args[0]));NAPI_CALL(env, napi_get_value_double(env, args[1], &addonData->args[1]));...
}
  • Callback方式在addCallback传入的是三个参数,Promise方式在addPromise传入的是两个参数。

创建异步工作项

  • 同Callback方式一样在创建异步工作项前,分别声明2个函数,分别用作于napi_create_async_work()函数的execute、complete参数。

  • 异步工作项创建OK后,将其存入上下文数据的asyncWork属性,并调用napi_queue_async_work()将异步工作项加入调度队列,由异步work线程池统一调度,原生方法返回Promise对象退出。

// 用户提供的上下文数据,在原生方法(初始化数据)、executeCB、completeCB之间传递数据
struct AddonData {napi_async_work asyncWork = nullptr;napi_deferred deferred = nullptr;double args[2] = {0};double result = 0;
};static napi_value addPromise(napi_env env, napi_callback_info info) {...// 创建async work,创建成功后通过最后一个参数(addonData->asyncWork)用于后续在C++的异步线程中返回真正的计算结果napi_value resourceName = nullptr;napi_create_string_utf8(env, "addAsyncCallback", NAPI_AUTO_LENGTH, &resourceName);napi_create_async_work(env, nullptr, resourceName, addExecuteCB, addPromiseCompleteCB, (void *)addonData,&addonData->asyncWork);// 将刚创建的async work加到队列,由底层去调度执行napi_queue_async_work(env, addonData->asyncWork);// 原生方法返回promisereturn promise;
}

execute 回调处理

此处完全同Callback方式,无需修改。

// 业务逻辑处理函数,由worker线程池调度执行。
static void addExecuteCB(napi_env env, void *data) {AddonData *addonData = (AddonData *)data;// 执行复杂计算,不阻塞主线程。此处用一个加法简单示意。addonData->result = addonData->args[0] + addonData->args[1];
}

complete 回调处理

  • 调用NAPI提供的napi_resolve_deferred() 或 napi_reject_deferred() 返回数据。之后释放过程中创建的napi_ref引用对象、异步工作项等对象。
static void addPromiseCompleteCB(napi_env env, napi_status status, void *data) {AddonData *addonData = (AddonData *)data;napi_value result = nullptr;napi_create_double(env, addonData->result, &result);napi_resolve_deferred(env, addonData->deferred, result);// 删除napi_ref对象if (addonData->callback != nullptr) {napi_delete_reference(env, addonData->callback);}// 删除异步工作项napi_delete_async_work(env, addonData->asyncWork);delete addonData;addonData = nullptr;
}

规范异步接口

hellonapi.cpp

#include <string.h>
#include<stdio.h>
#include "napi/native_node_api.h"
#include "napi/native_api.h"struct AddonData {napi_async_work asyncWork = nullptr;napi_deferred deferred = nullptr;napi_ref callback = nullptr;double args[2] = {0};double result = 0;
};// 业务逻辑处理函数,由worker线程池调度执行。
static void addExecuteCB(napi_env env, void *data) {AddonData *addonData = (AddonData *)data;// 执行复杂计算,不阻塞主线程。此处用一个加法简单示意。addonData->result = addonData->args[0] + addonData->args[1];
}// 业务逻辑处理完成回调函数,在业务逻辑处理函数执行完成或取消后触发,由EventLoop线程中执行。
static void addCallbackCompleteCB(napi_env env, napi_status status, void *data) {AddonData *addonData = (AddonData *)data;napi_value callback = nullptr;napi_get_reference_value(env, addonData->callback, &callback);napi_value undefined = nullptr;napi_get_undefined(env, &undefined);napi_value result = nullptr;napi_create_double(env, addonData->result, &result);napi_value callbackResult = nullptr;// 执行回调函数napi_call_function(env, undefined, callback, 1, &result, &callbackResult);// 删除napi_ref对象if (addonData->callback != nullptr) {napi_delete_reference(env, addonData->callback);}// 删除异步工作项napi_delete_async_work(env, addonData->asyncWork);delete addonData;
}static void addPromiseCompleteCB(napi_env env, napi_status status, void *data) {AddonData *addonData = (AddonData *)data;napi_value result = nullptr;napi_create_double(env, addonData->result, &result);napi_resolve_deferred(env, addonData->deferred, result);// 删除napi_ref对象if (addonData->callback != nullptr) {napi_delete_reference(env, addonData->callback);}// 删除异步工作项napi_delete_async_work(env, addonData->asyncWork);delete addonData;
}static napi_value addAsync(napi_env env, napi_callback_info info) {// 获取3个参数,值的类型是js类型(napi_value)size_t argc = 3;napi_value args[3];napi_value thisArg = nullptr;NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisArg, nullptr));// 获取并判断js参数类型napi_valuetype valuetype0;NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0));napi_valuetype valuetype1;NAPI_CALL(env, napi_typeof(env, args[1], &valuetype1));if (valuetype0 != napi_number || valuetype1 != napi_number) {napi_throw_type_error(env, nullptr, "Wrong arguments. 2 numbers expected.");return NULL;}// 异步工作项上下文用户数据,传递到异步工作项的execute、complete中传递数据auto addonData = new AddonData{.asyncWork = nullptr,};if (argc == 2) {// 创建promisenapi_value promise = nullptr;napi_deferred deferred = nullptr;NAPI_CALL(env, napi_create_promise(env, &deferred, &promise));addonData->deferred = deferred;// 将接收到的参数传入NAPI_CALL(env, napi_get_value_double(env, args[0], &addonData->args[0]));NAPI_CALL(env, napi_get_value_double(env, args[1], &addonData->args[1]));// 创建async work,创建成功后通过最后一个参数(addonData->asyncWork)返回async work的handlenapi_value resourceName = nullptr;napi_create_string_utf8(env, "addPromise", NAPI_AUTO_LENGTH, &resourceName);napi_create_async_work(env, nullptr, resourceName, addExecuteCB, addPromiseCompleteCB, (void *)addonData,&addonData->asyncWork);// 将刚创建的async work加到队列,由底层去调度执行napi_queue_async_work(env, addonData->asyncWork);// 返回promisereturn promise;} else {napi_valuetype valuetype2;NAPI_CALL(env, napi_typeof(env, args[2], &valuetype2));if (valuetype2 != napi_function) {napi_throw_type_error(env, nullptr, "Callback function expected.");return NULL;}// 将接收到的参数传入用户自定义上下文数据NAPI_CALL(env, napi_get_value_double(env, args[0], &addonData->args[0]));NAPI_CALL(env, napi_get_value_double(env, args[1], &addonData->args[1]));NAPI_CALL(env, napi_create_reference(env, args[2], 1, &addonData->callback));// 创建async work,创建成功后通过最后一个参数接收async work的handlenapi_value resourceName = nullptr;napi_create_string_utf8(env, "addCallback", NAPI_AUTO_LENGTH, &resourceName);napi_create_async_work(env, nullptr, resourceName, addExecuteCB, addCallbackCompleteCB, (void *)addonData,&addonData->asyncWork);// 将刚创建的async work加到队列,由底层去调度执行napi_queue_async_work(env, addonData->asyncWork);// 原生方法返回空对象napi_value result = 0;NAPI_CALL(env, napi_get_null(env, &result));return result;}
}// napi_addon_register_func
static napi_value registerFunc(napi_env env, napi_value exports) {static napi_property_descriptor desc[] = {DECLARE_NAPI_FUNCTION("addAsync", addAsync),};NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));return exports;
}// 1.先定义napi_module,指定当前NAPI模块对应的模块名
//以及模块注册对外接口的处理函数,具体扩展的接口在该函数中声明
// nm_modname: 模块名称,对应eTS代码为import nm_modname from '@ohos.ohos_shared_library_name'
//示例对应eTS代码为:import hellonapi from '@ohos.hellonapi'
static napi_module hellonapiModule = {.nm_version = 1,.nm_flags = 0,.nm_filename = nullptr,.nm_register_func = registerFunc, // 模块对外接口注册函数.nm_modname = "hellonapi",  // 自定义模块名.nm_priv = ((void*)0),.reserved = { 0 },
};//3.模块定义好后,调用NAPI提供的模块注册函数napi_module_register(napi_module* mod)函数注册到系统中。
// register module,设备启动时自动调用此constructor函数,把模块定义的模块注册到系统中
extern "C" __attribute__((constructor)) void hellonapiModuleRegister()
{napi_module_register(&hellonapiModule);
}

index.ets

import prompt from '@system.prompt';
import hellonapi from '@ohos.hellonapi'@Entry
@Component
struct TestAdd {build() {Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {Button("hellonapi.addAsync(x, y, callback)").margin(10).fontSize(20).onClick(() => {let num1 = 123, num2 = 456hellonapi.addAsync(num1, num2, (result) => {prompt.showToast({ message: `hellonapi.addAsync(${num1}, ${num2}) = ${result}` })})})Button("hellonapi.addAsync(x, y).then(...)").margin(10).fontSize(20).onClick(() => {let num1 = 123, num2 = 456hellonapi.addAsync(num1, num2).then((result) => {prompt.showToast({ message: `hellonapi.addAsync(${num1}, ${num2}) = ${result}` })})})}.width('100%').height('100%')}
}

@ohos.hellonapi.d.ts

declare namespace hellonapi {function addAsync(num1: number, num2: number, callback:(result: number) => void): void;function addAsync(num1: number, num2: number): Promise<number>;/*** ** @since 9* @syscap SystemCapability.Ability.AbilityRuntime.AbilityCore*/}
export default hellonapi;

异步方法和同步方法.ts接口文件

同步方法

  • 同步方法调用之后,将阻塞住JS线程直至获取到返回值。

  • 命名:动词+Sync或动词+名词+Sync

  • 格式:

    • 无参:方法名()
    • 有参:方法名Sync(必填参数[, 可选参数])
  • 返回值:有

  • 声明文件模板

declare namespace 模块名 
{/**
* 方法描述
* @note 特殊说明
* @since (可选,方法支持版本与模块不一致时需标明)
* @sysCap 系统能力
* @devices 支持设备 (可选,支持设备类型与模块不一致时需标明)
* @param 参数 参数说明(可选,没有参数或参数用interface包含时不需要标明)
* @return 返回值说明(可选,没有返回值或返回值用interface包含时不需要标明)
*/// 无参
function 方法名Sync(): 返回值类型;// 有参
function 方法名Sync(必填参数: 参数类型, options?: 可选参数类型): 返回值类型;interface 可选参数类型 {
参数名: 参数类型;
}
}export default 模块名;
  • 示例
declare namespace hellonapi {function add(num1: number, num2: number): number;/*** ** @since 9* @syscap SystemCapability.Ability.AbilityRuntime.AbilityCore*/}
export default hellonapi;

异步方法

  • 异步方法调用整个过程不会阻碍调用者的工作。

  • 命名:动词或动词+名词

  • 格式:

    • 无参:方法名([回调函数])
    • 有参:方法名(必填参数[, 可选参数][, 回调函数])
  • 返回值

    • 若回调函数非空,则返回void
    • 若回调函数为空,则返回Promise实例对象
  • 声明文件模板

declare namespace 模块名 {/*** 方法描述* @note 特殊说明* @since (可选,方法支持版本与模块不一致时需标明)* @sysCap 系统能力* @devices 支持设备 (可选,支持设备类型与模块不一致时需标明)* @param 参数 参数说明(可选,没有参数或参数用interface包含时不需要标明)*/// 无参
function 方法名(callback: AsyncCallback<结果数据类型>): void;
function 方法名(): Promise<结果数据类型>;// 有参
function 方法名(必填参数: 参数类型, callback: AsyncCallback<结果数据类型>): void;
function 方法名(必填参数: 参数类型, options: 可选参数类型, callback: AsyncCallback<结果数据类型>): void;
function 方法名(必填参数: 参数类型, options?: 可选参数类型): Promise<结果数据类型>;interface 可选参数类型 {参数名: 参数类型;
}
}export default 模块名;
  • 示例
declare namespace hellonapi {function addAsync(num1: number, num2: number, callback:(result: number) => void): void;function addAsync(num1: number, num2: number): Promise<number>;/*** ** @since 9* @syscap SystemCapability.Ability.AbilityRuntime.AbilityCore*/}
export default hellonapi;	

NAPI中的数据类型

  • NAPI使用的数据类型和Node.js N-API保持一致。OpenHarmony的NAPI(Native API)组件是一套对外接口基于Node.js N-API规范开发的原生模块扩展开发框架。
    通过查看foundation/arkui/napi/interfaces/inner_api/napi/native_node_api.h(编写NAPI拓展模块hellonapi.cpp需要包含的头文件)可以知道OpenHarmony基本的NAPI数据类型。

#include <js_native_api.h>中的js_native_api.h在ohos3.2beta3版本源码目录下路径为prebuilts/build-tools/common/nodejs/node-v12.18.4-linux-x64/include/node/js_native_api_types.h。

然后再分析prebuilts/build-tools/common/nodejs/node-v12.18.4-linux-x64/include/node/js_native_api_types.h和third_party/node/src/js_native_api_types.h内容的差别。

两者内容一致,可以推测OpenHarmony中基本的NAPI数据类型和Node.js N-API中的保持一致。而接口名方面,napi提供的接口名与三方Node.js一致,目前支持部分接口,详情见libnapi.ndk.json文件

// JSVM API types are all opaque pointers for ABI stability
// typedef undefined structs instead of void* for compile time type safety
typedef struct napi_env__* napi_env;
typedef struct napi_value__* napi_value;
typedef struct napi_ref__* napi_ref;
typedef struct napi_handle_scope__* napi_handle_scope;
typedef struct napi_escapable_handle_scope__* napi_escapable_handle_scope;
typedef struct napi_callback_info__* napi_callback_info;
typedef struct napi_deferred__* napi_deferred;

预处理器发现 #include 指令后,就会寻找指令后面<>中的文件名,并把这个文件的内容包含到当前文件中。被包含文件中的文本将替换源代码文件中的#include 指令

  • 以typedef struct napi_env__* napi_env为例,搜遍Node.js的源码都找不到napi_value__定义,那这个定义是什么意思呢?c语言中,允许定义一个没有定义的结构体的指针。所以napi_value其实就是一个一级指针。他不需要类型信息。

typedef作用就是定义类型别名

关于NAPI标准库中导出的符号列表

  • NAPI它基于Node.js N-API规范开发,因此可参考Node.js N-API了解NAPI标准库中符号列表。本文以3.2beta3源码中的node三方库为例,从third_party/node/README.OpenSource中可得知3.2beta3移植的node版本为14.19.1,因此可参考的Node.js N-API链接为14.19.1版本,如下:https://nodejs.org/docs/latest-v14.x/api/n-api.html

  • 标准库中导出的符号列表

符号类型符号名备注
FUNCnapi_module_register
FUNCnapi_get_last_error_info
FUNCnapi_throw
FUNCnapi_throw_error
FUNCnapi_throw_type_error
FUNCnapi_throw_range_error
FUNCnapi_is_error
FUNCnapi_create_error
FUNCnapi_create_type_error
FUNCnapi_create_range_error
FUNCnapi_get_and_clear_last_exception
FUNCnapi_is_exception_pending
FUNCnapi_fatal_error
FUNCnapi_open_handle_scope
FUNCnapi_close_handle_scope
FUNCnapi_open_escapable_handle_scope
FUNCnapi_close_escapable_handle_scope
FUNCnapi_escape_handle
FUNCnapi_create_reference
FUNCnapi_delete_reference
FUNCnapi_reference_ref
FUNCnapi_reference_unref
FUNCnapi_get_reference_value
FUNCnapi_create_array
FUNCnapi_create_array_with_length
FUNCnapi_create_arraybuffer
FUNCnapi_create_external
FUNCnapi_create_external_arraybuffer
FUNCnapi_create_object
FUNCnapi_create_symbol
FUNCnapi_create_typedarray
FUNCnapi_create_dataview
FUNCnapi_create_int32
FUNCnapi_create_uint32
FUNCnapi_create_int64
FUNCnapi_create_double
FUNCnapi_create_string_latin1
FUNCnapi_create_string_utf8
FUNCnapi_get_array_length
FUNCnapi_get_arraybuffer_info
FUNCnapi_get_prototype
FUNCnapi_get_typedarray_info
FUNCnapi_get_dataview_info
FUNCnapi_get_value_bool
FUNCnapi_get_value_double
FUNCnapi_get_value_external
FUNCnapi_get_value_int32
FUNCnapi_get_value_int64
FUNCnapi_get_value_string_latin1
FUNCnapi_get_value_string_utf8
FUNCnapi_get_value_uint32
FUNCnapi_get_boolean
FUNCnapi_get_global
FUNCnapi_get_null
FUNCnapi_get_undefined
FUNCnapi_coerce_to_bool
FUNCnapi_coerce_to_number
FUNCnapi_coerce_to_object
FUNCnapi_coerce_to_string
FUNCnapi_typeof
FUNCnapi_instanceof
FUNCnapi_is_array
FUNCnapi_is_arraybuffer
FUNCnapi_is_typedarray
FUNCnapi_is_dataview
FUNCnapi_is_date
FUNCnapi_strict_equals
FUNCnapi_get_property_names
FUNCnapi_set_property
FUNCnapi_get_property
FUNCnapi_has_property
FUNCnapi_delete_property
FUNCnapi_has_own_property
FUNCnapi_set_named_property
FUNCnapi_get_named_property
FUNCnapi_has_named_property
FUNCnapi_set_element
FUNCnapi_get_element
FUNCnapi_has_element
FUNCnapi_delete_element
FUNCnapi_define_properties
FUNCnapi_call_function
FUNCnapi_create_function
FUNCnapi_get_cb_info
FUNCnapi_get_new_target
FUNCnapi_new_instance
FUNCnapi_define_class
FUNCnapi_wrap
FUNCnapi_unwrap
FUNCnapi_remove_wrap
FUNCnapi_create_async_work
FUNCnapi_delete_async_work
FUNCnapi_queue_async_work
FUNCnapi_cancel_async_work
FUNCnapi_get_node_version
FUNCnapi_get_version
FUNCnapi_create_promise
FUNCnapi_resolve_deferred
FUNCnapi_reject_deferred
FUNCnapi_is_promise
FUNCnapi_run_script
FUNCnapi_get_uv_event_loop

Native API接口说明

符号类型符号名备注
FUNCnapi_run_script_path运行JavaScript文件

关于镜像文件的编译

  • 初次编译OpenHarmony标准系统镜像时,会完整的编译出boot_linux.imgconfig.cfgMiniLoaderAll.binparameter.txtramdisk.imgresource.imgsystem.imguboot.imgupdater.imguserdata.imgvendor.img文件
  • 后面自己修改源码(不涉及内核源码)后编译,可以烧录自己编译的system.imgvendor.imgupdater.imguserdata.imgramdisk.img

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

这篇关于三方库移植之NAPI开发[4]异步调用:CallbackPromise的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/898895

相关文章

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

如何在页面调用utility bar并传递参数至lwc组件

1.在app的utility item中添加lwc组件: 2.调用utility bar api的方式有两种: 方法一,通过lwc调用: import {LightningElement,api ,wire } from 'lwc';import { publish, MessageContext } from 'lightning/messageService';import Ca

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

【区块链 + 人才服务】区块链集成开发平台 | FISCO BCOS应用案例

随着区块链技术的快速发展,越来越多的企业开始将其应用于实际业务中。然而,区块链技术的专业性使得其集成开发成为一项挑战。针对此,广东中创智慧科技有限公司基于国产开源联盟链 FISCO BCOS 推出了区块链集成开发平台。该平台基于区块链技术,提供一套全面的区块链开发工具和开发环境,支持开发者快速开发和部署区块链应用。此外,该平台还可以提供一套全面的区块链开发教程和文档,帮助开发者快速上手区块链开发。

Vue3项目开发——新闻发布管理系统(六)

文章目录 八、首页设计开发1、页面设计2、登录访问拦截实现3、用户基本信息显示①封装用户基本信息获取接口②用户基本信息存储③用户基本信息调用④用户基本信息动态渲染 4、退出功能实现①注册点击事件②添加退出功能③数据清理 5、代码下载 八、首页设计开发 登录成功后,系统就进入了首页。接下来,也就进行首页的开发了。 1、页面设计 系统页面主要分为三部分,左侧为系统的菜单栏,右侧

v0.dev快速开发

探索v0.dev:次世代开发者之利器 今之技艺日新月异,开发者之工具亦随之进步不辍。v0.dev者,新兴之开发者利器也,迅速引起众多开发者之瞩目。本文将引汝探究v0.dev之基本功能与优势,助汝速速上手,提升开发之效率。 何谓v0.dev? v0.dev者,现代化之开发者工具也,旨在简化并加速软件开发之过程。其集多种功能于一体,助开发者高效编写、测试及部署代码。无论汝为前端开发者、后端开发者