Openharmony应用NAPI详解--进阶篇2

NAPI面向C++的异步接口(promise)

promise方式的处理方式

承接上文,与callback方式不同的是,promise对象由C++侧创建以返回值的方式传递回js/ets侧,promise对象存储异步执行的结果。

// foundation/filemanagement/file_api/interfaces/kits/js/src/common/napi/n_async/n_async_work_promise.cpp
NVal NAsyncWorkPromise::Schedule(string procedureName, NContextCBExec cbExec, NContextCBComplete cbComplete)
{
    ctx_->cbExec_ = move(cbExec);
    ctx_->cbComplete_ = move(cbComplete);

    napi_status status;
    napi_value result = nullptr;
    status = napi_create_promise(env_, &ctx_->deferred_, &result);
    if (status != napi_ok) {
        HILOGE("INNER BUG. Cannot create promise for %{public}d", status);
        return NVal();
    }

    napi_value resource = NVal::CreateUTF8String(env_, procedureName).val_;
    status = napi_create_async_work(env_, nullptr, resource, PromiseOnExec, PromiseOnComplete, ctx_, &ctx_->awork_);
    if (status != napi_ok) {
        HILOGE("INNER BUG. Failed to create async work for %{public}d", status);
        return NVal();
    }

    status = napi_queue_async_work(env_, ctx_->awork_);
    if (status != napi_ok) {
        HILOGE("INNER BUG. Failed to queue async work for %{public}d", status);
        return NVal();
    }

    ctx_ = nullptr; // The ownership of ctx_ has been transfered
    return { env_, result };
}

1.napi_create_promise创建创建Promise,返回promise、deferred 二个对象, promise用于主线程方法返回。 deferred对象用于resolve、reject处理。

首先先分析下napi_create_promise的方法定义

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表示转换成功,其他值失败。

2.执行napi_create_async_work异步线程后,将deferred对象,通过napi_queue_async_work将创建的async work添加到队列,由NAPI框架的底层去调度后执行。

3.result即为返回的promise对象。

napi_create_async_work中的异步处理execute和complete方法,分别对应PromiseOnExec, PromiseOnComplete。处理完成后将ctx->res_结果更新至deferred的对象中。

static void PromiseOnExec(napi_env env, void *data)
{
...
}

static void PromiseOnComplete(napi_env env, napi_status status, void *data)
{
...
    if (!ctx->res_.TypeIsError(true)) {
        napi_status status = napi_resolve_deferred(env, ctx->deferred_, ctx->res_.val_);
        if (status != napi_ok) {
            HILOGE("Internal BUG, cannot resolve promise for %{public}d", status);
        }
    } else {
        napi_status status = napi_reject_deferred(env, ctx->deferred_, ctx->res_.val_);
        if (status != napi_ok) {
            HILOGE("Internal BUG, cannot reject promise for %{public}d", status);
        }
    }
    ctx->deferred_ = nullptr;
    napi_delete_async_work(env, ctx->awork_);
    delete ctx;
}

最终返回临时结果NVal给js调用 (callback接口返回的是void, promise接口返回的是返回临时结果给js调用)。

此文讲解NAPI选用的分布式文件子系统,此实例将NAPI的接口封装成了多个操作的类(NAsyncWorkPromise、NAsyncWorkCallback、NVal等),对JS如何通过NAPI的调用C++调用流程与使用方式有一定的了解。如果想了解更多的NAPI的使用细节,可以在Openharmony的其它的子系统中查看其它的NAPI方法。以下提供NAPI的其它的一些接口说明和注意事项。

NAPI类型与接口说明

typedef enum {
  napi_undefined,
  napi_null,
  napi_boolean,
  napi_number,
  napi_string,
  napi_symbol,
  napi_object,
  napi_function,
  napi_external,
  napi_bigint
} napi_valuetype;
//对应了ECMAScript标准中定义的Undefined、Null、Boolean、Number、String、Symbol、Object、Function和BigInt九种数据类型。另外,napi_valuetype还包括了一个napi_external类型,其表示没有任何属性也没有任何原型的对象。

napi_status napi_get_value_double(
  napi_env env,
  napi_value value,     // 获取的Javascript值
  double *result        // 用于保存对应的double类型值
);

// napi_create_double创建其对应的Javascript double值result
napi_status napi_create_double(
  napi_env env,
  double value,         // double类型的值
  napi_value *result    // 保存创建的Javascript值
);

// napi_create_string_utf8用于创建一个UTF-8类型的字符串对象,其值来自于参数传递的UTF-8编码字符串
napi_status napi_create_string_utf8(napi_env env,
  const char *str,
  size_t length,
  napi_value* result
);

napi_status napi_get_value_double(
  napi_env env,
  napi_value value,     // 获取的Javascript值
  double *result        // 用于保存对应的double类型值
);

// napi_create_double创建其对应的Javascript double值result
napi_status napi_create_double(
  napi_env env,
  double value,         // double类型的值
  napi_value *result    // 保存创建的Javascript值
);

// napi_create_string_utf8用于创建一个UTF-8类型的字符串对象,其值来自于参数传递的UTF-8编码字符串
napi_status napi_create_string_utf8(napi_env env,
  const char *str,
  size_t length,
  napi_value* result
);

// C/C++类型转NAPI类型
napi_status napi_create_object(napi_env env, napi_value *value);
napi_status napi_create_array(napi_env env, napi_value* value);

//异步方法需要在不同线程中传递各种业务数据,定义一个结构体保存这些被传递的信息
struct MyAsyncContext {
    napi_env env = nullptr; // napi运行环境
    napi_async_work work = nullptr; // 异步工作对象
    napi_deferred deferred = nullptr; // 延迟执行对象(用于promise方式返回计算结果)
    napi_ref callbackRef = nullptr; // js callback function的引用对象 (用于callback方式返回计算结果)
    int32_t status;
    napi_value value[3];
};

其它一些API参考官方文档:

https://www.apiref.com/nodejs-zh/n-api.html

注意事项

1.回调函数callback字段使用napi_ref类型,不能使用napi_value类型。因napi_value类型对象生命周期在原生方法结束时结束,导致在work线程、EventLoop线程中获取不到,而napi_ref类型生命周期大于方法的。

2.NAPI在Openharmony的V3.2版本之后,添加了NAPI框架生成工具(napi_generator)子系统,故名思义,可以自动生成NAPI的框架,后续如果有读者对此有兴趣,可以专门开辟篇章进行说明。

后续更精彩

1.关于service ability的前世今生

2.L0设备在Openharmony基座上的开发实例

3.鸿蒙编译构建流程

你可能感兴趣的:(openharmony,NAPI)