场景1:js 侧接收 C++ 侧创建的 Promise 实例
基本流程
- C++ 侧调用 napi_create_promise 创建新的的延迟对象 deferred 与延迟对象相关联的 JavaScript promise。
- promise 实例通过接口返回给 JS 侧使用。
- deferrd 延迟对象用全局上下文对象保存,只要 deferrd 对象没被销毁,C++ 侧、就可以在任意方法内、任意时机去控制 JS 侧 Promise 实例的状态(fulfilled/rejected)。
示例代码
JS 侧
Row() {
Text("getPromise")
.fontSize(50)
.fontWeight(FontWeight.Bold)
.onClick(() => {
// 接收 c++ 侧 传来的 promise 并使用
let promise1 = testNapi.getPromise();
promise1.then((val)=>{
hilog.info(0x0000, 'testTag', 'Test NAPI getPromise res is %{public}s', JSON.stringify(val));
})
})
}
C++ 侧
// 定义 promise 相关数据结构体(全局)
struct promiseInfo {
napi_async_work worker; // 用来存储操作异步 work 句柄
napi_deferred deferred; // 存储延迟对象,用于操作 promise
char *val; // 存储 resolve/reject 函数调用时的参数
};
// 全局实例化 结构体数据
struct promiseInfo data = { nullptr, nullptr, 0 };
// 异步 work 执行的回调
void execute(napi_env env, void* data) {
struct promiseInfo *arg = (struct promiseInfo *)data;
arg->val = "success";
}
// 异步 work 执行结束时,调用的回调
void complete(napi_env env, napi_status status, void *data) {
struct promiseInfo *arg = (struct promiseInfo *)data;
napi_value val;
if (true) {
// 执行 reslove 操作
napi_create_string_utf8(env, arg->val, NAPI_AUTO_LENGTH, &val);
napi_resolve_deferred(env, arg->deferred, val);
} else {
// 执行 reject 操作
napi_create_string_utf8(env, "error", NAPI_AUTO_LENGTH, &val);
napi_reject_deferred(env, arg->deferred, val);
}
napi_delete_async_work(env, arg->worker);
arg->deferred = nullptr;
}
static napi_value getPromise(napi_env env, napi_callback_info info)
{
napi_value promise;
napi_value resourceName;
struct promiseInfo *ptr = &data;
// 创建新的的延迟对象 deferred 与延迟对象相关联的 JavaScript promise。
napi_create_promise(env, &ptr->deferred, &promise);
napi_create_string_utf8(env, "test", NAPI_AUTO_LENGTH, &resourceName);
// 创建异步 work
napi_create_async_work(env, nullptr, resourceName, execute, complete, ptr, &ptr->worker);
// 把异步 work 放到队列中,等待执行
napi_queue_async_work(env, ptr->worker);
return promise;
}
场景2:C++ 侧使用从 JS 侧获取的 Promise 实例
JS 侧
调用 handlePromise,传入返回值是 promise 实例的函数
Row() {
Text("handlePromise")
.fontSize(50)
.fontWeight(FontWeight.Bold)
.onClick(() => {
let res = testNapi.handlePromise(()=>{
return new Promise((resolve, reject) => {
let v = "resolve success";
resolve(v);
})
})
hilog.info(0x0000, 'testTag', 'Test NAPI handlePromise res is %{public}s', JSON.stringify(res))
})
}
C++ 侧
1、接收 从 JS 侧传来的函数参数。 2、调用函数,得到返回值,一个 promise 实例。 3、获取 promise 实例的 then、catch 属性方法,并使用相应的函数参数进行调用。
// 创建 then 回调函数
auto successCb = [](napi_env env, napi_callback_info info) -> napi_value {
size_t argc = 1;
napi_value args[1] = { nullptr };
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
char v[20];
size_t res;
napi_get_value_string_utf8(env, args[0], v, 20, &res);
return nullptr;
};
// 创建 catch 回调函数
auto errorCb= [](napi_env env, napi_callback_info info) -> napi_value {
size_t argc = 1;
napi_value args[1] = { nullptr };
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
char v[20];
size_t res;
napi_get_value_string_utf8(env, args[0], v, 20, &res);
return nullptr;
};
static napi_value handlePromise(napi_env env, napi_callback_info info) {
size_t argsNum = 1;
napi_value args[1] = { nullptr };
napi_value context;
napi_get_cb_info(env, info, &argsNum, args, &context, nullptr);
napi_value promise;
// c++ 侧调用从 JS 侧传参过来的函数,函数返回值是一个 Promise 实例
napi_call_function(env, context, args[0], 0, nullptr, &promise);
// promiseThen = promise.then,把 promise 实例的 then 属性地址赋值给 promiseThen
napi_value promiseThen;
napi_get_named_property(env, promise, "then", &promiseThen);
// promiseCatch = promise.catch
napi_value promiseCatch;
napi_get_named_property(env, promise, "catch", &promiseCatch);
// then 回调函数转换成 N-API value 类型
napi_value successFunc;
napi_create_function(env, "successFunc", NAPI_AUTO_LENGTH, successCb, nullptr, &successFunc);
// catch 回调函数转换成 N-API value 类型
napi_value errorFunc;
napi_create_function(env, "errorFunc", NAPI_AUTO_LENGTH, errorCb, nullptr, &errorFunc);
napi_value ret;
// 执行 promiseThen(successCb),相当于 promise.then(() => {})
napi_call_function(env, promise, promiseThen, 1, &successFunc, &ret);
// 执行 promiseCatch(errorCb),相当于 promise.catch(() => {})
napi_call_function(env, promise, promiseCatch, 1, &errorFunc, &ret);
return context;
}