• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Calling Back ArkTS APIs in a Non-ArkTS Thread
2
3## When to Use
4
5ArkTS is a single-thread language. Normally, all operations on an ArkTS object through Node-API interfaces must be performed by the same ArkTS thread. The following example describes how to use **napi_get_uv_event_loop** and **uv_queue_work** to call back ArkTS functions using Node-API in a non-ArkTS thread.
6
7## Example
8
91. Declare the APIs, configure compile settings, and register the module.
10
11   **Declare the APIs.**
12
13   ```ts
14   // index.d.ts
15   export const queueWork: (cb: (arg: number) => void) => void;
16   ```
17
18   **Configure compile settings.**
19
20   ```
21   // CMakeLists.txt
22   # Minimum version of CMake.
23   cmake_minimum_required(VERSION 3.4.1)
24   project(MyApplication)
25
26   set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
27
28   include_directories(${NATIVERENDER_ROOT_PATH}
29                       ${NATIVERENDER_ROOT_PATH}/include)
30   add_library(queue_work SHARED queue_work.cpp)
31   target_link_libraries(queue_work PUBLIC libace_napi.z.so libhilog_ndk.z.so libuv.so)
32   ```
33
34   **Register the module.**
35
36   ```cpp
37   // queue_work.cpp
38   EXTERN_C_START
39   static napi_value Init(napi_env env, napi_value exports)
40   {
41       napi_property_descriptor desc[] = {
42           { "queueWork", nullptr, QueueWork, nullptr, nullptr, nullptr, napi_default, nullptr }
43       };
44       napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
45       return exports;
46   }
47   EXTERN_C_END
48
49   static napi_module nativeModule = {
50       .nm_version = 1,
51       .nm_flags = 0,
52       .nm_filename = nullptr,
53       .nm_register_func = Init,
54       .nm_modname = "queue_work",
55       .nm_priv = nullptr,
56       .reserved = { 0 },
57   };
58
59   extern "C" __attribute__((constructor)) void RegisterQueueWorkModule()
60   {
61       napi_module_register(&nativeModule);
62   }
63   ```
64
652. Obtain the loop corresponding to **env** and throw a task to an ArkTS thread.
66
67   ```cpp
68   // queue_work.cpp
69   #include <thread>
70
71   #include "napi/native_api.h"
72   #include "uv.h"
73
74   struct CallbackContext {
75       napi_env env = nullptr;
76       napi_ref callbackRef = nullptr;
77       int32_t retData = 0;
78   };
79
80   void StartThread(CallbackContext* context)
81   {
82       // Obtain the loop corresponding to the ArkTS thread from env, which must be saved when the JS callback is registered.
83       uv_loop_s* loop = nullptr;
84       napi_get_uv_event_loop(context->env, &loop);
85
86       // Create uv_work_t to pass private data. Note that memory must be released after the callback is complete. The logic for generating the returned data is omitted here. In this example, int 1 is returned.
87       uv_work_t* work = new uv_work_t;
88       context->retData = 1;
89       work->data = context;
90
91       // Throw a work object to the ArkTS thread.
92       uv_queue_work(
93           loop,
94           work,
95           // The work_cb callback is executed in another worker thread to process asynchronous or time-consuming tasks. After the callback is executed, the subsequent callback is executed. In this example, you do not need to perform the task.
96           [](uv_work_t* work) {},
97           // The after_work_cb callback is executed in the ArkTS thread corresponding to env.
98           [](uv_work_t* work, int status) {
99               CallbackContext* context = reinterpret_cast<CallbackContext*>(work->data);
100               napi_handle_scope scope = nullptr;
101               // Open the handle scope to manage the lifecycle of napi_value. Otherwise, memory leakage may occur.
102               napi_open_handle_scope(context->env, &scope);
103               if (scope == nullptr) {
104                   return;
105               }
106
107               // Call back the ArkTS function.
108               napi_value callback = nullptr;
109               napi_get_reference_value(context->env, context->callbackRef, &callback);
110               napi_value retArg;
111               napi_create_int32(context->env, context->retData, &retArg);
112               napi_value ret;
113               napi_call_function(context->env, nullptr, callback, 1, &retArg, &ret);
114               napi_delete_reference(context->env, context->callbackRef);
115
116               // Close the handle scope to release napi_value.
117               napi_close_handle_scope(context->env, scope);
118
119               if (work != nullptr) {
120                   delete work;
121               }
122               delete context;
123           }
124       );
125   }
126
127   static napi_value QueueWork(napi_env env, napi_callback_info info)
128   {
129       size_t argc = 1;
130       napi_value argv[1] = {nullptr};
131       napi_value thisVar = nullptr;
132       void *data = nullptr;
133       napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
134
135       // Check parameters.
136       if (argc < 1) {
137           napi_throw_error(env, "ParameterError", "one param expected");
138           return nullptr;
139       }
140       napi_valuetype valueType = napi_undefined;
141       napi_typeof(env, argv[0], &valueType);
142       if (valueType != napi_function) {
143           napi_throw_error(env, "ParameterError", "function expected");
144           return nullptr;
145       }
146
147       // Save env and the callback for subsequent invoking.
148       auto asyncContext = new CallbackContext();
149       asyncContext->env = env;
150       napi_create_reference(env, argv[0], 1, &asyncContext->callbackRef);
151       // Simulate the logic for throwing a work object to a non-JS thread.
152       std::thread testThread(StartThread, asyncContext);
153       testThread.detach();
154
155       return nullptr;
156   }
157   ```
158
1593. Sample ArkTS code.
160
161   ```ts
162   import { queueWork }  from 'libqueue_work.so'
163
164   queueWork((result: number) => {
165       console.log("result = " + result);
166   });
167   ```
168