异步流程介绍
ArkTS是单线程的,其通过事件循环机制来处理异步任务,这一特性,同样也深入影响了Node-API的模块开发。在Native线程中既要保证没有多线程问题,又要保证任务的正确执行。
基于threadsafe的实现
方案概述
针对在HarmonyOS中,Native子线程不能直接访问ArkTS主线程的资源的场景,Node-API提供了napi\_threadsafe\_function这一套线程安全函数接口,用来实现异步通信操作。下面介绍napi\_threadsafe\_function的方式。
实现流程
- 应用侧传入需要执行的异步任务。
- Native侧通过napi\_create\_threadsafe\_function创建线程安全函数,将callback注册到线程安全函数中,等待后续其他线程抛异步任务进行回调。
- 通过napi\_create\_async\_work,将ExecuteWork与WorkComplete添加为异步任务的执行回调与完成回调。
- 通过ExecuteWork函数进行业务处理,并执行线程安全函数,通过WorkComplete函数进行任务执行完成后的资源清理回收工作。
- 通过注册给线程安全函数的callback回到主线程,然后通过napi\_call\_function调用ArkTS函数回到ArkTS侧。
- 在ArkTS线程中解析或拒绝promise的唯一方法。
代码实现
C++:
Native侧通过napi\_create\_threadsafe\_function创建线程安全函数,将callback注册到线程安全函数中,等待后续其他线程抛异步任务进行回调。
struct CallbackData { napi_threadsafe_function tsfn; napi_async_work work; }; static napi_value StartThread(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value jsCb = nullptr; CallbackData *callbackData = nullptr; napi_get_cb_info(env, info, &argc, &jsCb, nullptr, reinterpret_cast<void **>(&callbackData)); // 创建一个线程安全函数 napi_value resourceName = nullptr; napi_create_string_utf8(env, "Thread-safe Function Demo", NAPI_AUTO_LENGTH, &resourceName); napi_create_threadsafe_function(env, jsCb, nullptr, resourceName, 0, 1, callbackData, nullptr, callbackData, CallJs, &callbackData->tsfn); // 创建一个异步任务 napi_create_async_work(env, nullptr, resourceName, ExecuteWork, WorkComplete, callbackData, &callbackData->work); // 将异步任务加入到异步队列中 napi_queue_async_work(env, callbackData->work); return nullptr; }
通过ExecuteWork函数进行业务处理,并执行线程安全函数,通过WorkComplete函数进行任务执行完成后的资源清理回收工作。
static void ExecuteWork(napi_env env, void *data) { CallbackData_ThreadSafe *callbackData = reinterpret_cast<CallbackData_ThreadSafe *>(data); std::promise<std::string> promise; auto future = promise.get_future(); napi_call_threadsafe_function(callbackData->tsfn, &promise, napi_tsfn_nonblocking); try { auto result = future.get(); OH_LOG_INFO(LOG_APP, "XXX, Result from JS %{public}s", result.c_str()); } catch (const std::exception &e) { OH_LOG_INFO(LOG_APP, "XXX, Result from JS %{public}s", e.what()); } } static void WorkComplete(napi_env env, napi_status status, void *data) { CallbackData_ThreadSafe *callbackData = reinterpret_cast<CallbackData_ThreadSafe *>(data); napi_release_threadsafe_function(callbackData->tsfn, napi_tsfn_release); napi_delete_async_work(env, callbackData->work); callbackData->tsfn = nullptr; callbackData->work = nullptr; }
通过注册给线程安全函数的callback回到主线程,然后通过napi\_call\_function调用ArkTS 函数回到ArkTS侧。
static void CallJs(napi_env env, napi_value jsCb, void *context, void *data) { if (env == nullptr) { return; } napi_value undefined = nullptr; napi_value promise = nullptr; napi_get_undefined(env, &undefined); napi_call_function(env, undefined, jsCb, 0, nullptr, &promise); napi_value thenFunc = nullptr; if (napi_get_named_property(env, promise, "then", &thenFunc) != napi_ok) { return; } napi_value resolvedCallback; napi_value rejectedCallback; napi_create_function(env, "resolvedCallback", NAPI_AUTO_LENGTH, ResolvedCallback, data, &resolvedCallback); napi_create_function(env, "rejectedCallback", NAPI_AUTO_LENGTH, RejectedCallback, data, &rejectedCallback); napi_value argv[2] = {resolvedCallback, rejectedCallback}; napi_call_function(env, promise, thenFunc, 2, argv, nullptr); }
在ArkTS线程中解析或拒绝promise。
static napi_value ResolvedCallback(napi_env env, napi_callback_info info) { void *data = nullptr; size_t argc = 1; napi_value argv[1]; if (napi_get_cb_info(env, info, &argc, argv, nullptr, &data) != napi_ok) { return nullptr; } size_t result = 0; char buf[32] = {0}; napi_get_value_string_utf8(env, argv[0], buf, 32, &result); reinterpret_cast<std::promise<std::string> *>(data)->set_value(std::string(buf)); return nullptr; } static napi_value RejectedCallback(napi_env env, napi_callback_info info) { void *data = nullptr; if (napi_get_cb_info(env, info, nullptr, nullptr, nullptr, &data) != napi_ok) { return nullptr; } reinterpret_cast<std::promise<std::string> *>(data)->set_exception( std::make_exception_ptr(std::runtime_error("Error in jsCallback"))); return nullptr; }
TS:
import nativeModule from 'libentry.so';
// 应用侧传入需要执行的异步任务
let callback = (): Promise<string> => {
return new Promise((resolve) => {
setTimeout(() => {
resolve("string from promise");
}, 5000);
});
}
nativeModule.startThread(callback);
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。