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