1e41f4b71Sopenharmony_ci# Secure and Efficient N-API Development
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci## Introduction
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ciN-API, short for Node.js Addon Programming Interface, is a set of C++ APIs provided by Node.js. Shipped with the capabilities of the [V8 engine](https://v8.dev/docs), it is used to build Node.js native addons. By drawing on N-API, you can write high-performance Node.js modules in C++ while maintaining compatibility with Node.js.
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ciN-API provided in [ArkCompiler ArkTS runtime](https://gitee.com/openharmony/arkcompiler_ets_runtime), shipped with the capabilities of the Ark engine, provides the same basic functionality as described in the [Node.js documentation](https://nodejs.org/api/n-api.html).
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ciThis document is intended to provide guidance on secure and efficient N-API development. Designed with carefully curated use cases, it is structured into four parts: object lifetime management, cross-language invocation overhead, asynchronous operation, and thread security.
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ci## Object Lifetime Management
12e41f4b71Sopenharmony_ci
13e41f4b71Sopenharmony_ciAs N-API calls are made, handles to objects in the VM heap may be returned as **napi_value**s. These handles control the lifetime of the objects. Object handles are associated with a scope. The default lifespan of the scope is tied to the lifespan of the native method. In some real-world cases, however, an object may require a scope with a shorter or longer lifespan than that of the native method. This section describes how to use N-API functions to change the object lifespan.
14e41f4b71Sopenharmony_ci
15e41f4b71Sopenharmony_ci### Shortening Object Lifespan
16e41f4b71Sopenharmony_ci
17e41f4b71Sopenharmony_ciYou can use **napi_open_handle_scope** and **napi_close_handle_scope** to manage the lifetime of **napi_value**, so as to minimize the object lifespan and avoid memory leak.
18e41f4b71Sopenharmony_ci
19e41f4b71Sopenharmony_ciFor example, consider a method that has a **for** loop, which iterates through the elements in a large array:
20e41f4b71Sopenharmony_ci```cpp
21e41f4b71Sopenharmony_cifor (int i = 0; i < 1000000; i++) {
22e41f4b71Sopenharmony_ci napi_value result;
23e41f4b71Sopenharmony_ci napi_status status = napi_get_element(env, object, i, &result);
24e41f4b71Sopenharmony_ci if (status != napi_ok) {
25e41f4b71Sopenharmony_ci  break;
26e41f4b71Sopenharmony_ci }
27e41f4b71Sopenharmony_ci // do something with element
28e41f4b71Sopenharmony_ci}
29e41f4b71Sopenharmony_ci```
30e41f4b71Sopenharmony_ci
31e41f4b71Sopenharmony_ciIn this case, a large number of handles may be created, consuming substantial resources. To handle this case, N-API provides the function to establish a new scope to which newly created handles will be associated. Once those handles are no longer needed, the scope can be closed and any handles associated with the scope are invalidated.
32e41f4b71Sopenharmony_ci
33e41f4b71Sopenharmony_ci* The methods available to open and close scopes are **napi_open_handle_scope** and **napi_close_handle_scope**, respectively.
34e41f4b71Sopenharmony_ci* N-API only supports a single nested hierarchy of scopes. There is only one active scope at any time, and all new handles will be associated with that scope while it is active.
35e41f4b71Sopenharmony_ci* Scopes must be closed in the reverse order from which they are opened. In addition, all scopes created within a native method must be closed before returning from that method.
36e41f4b71Sopenharmony_ci
37e41f4b71Sopenharmony_ciThe following is an optimization based on the earlier example. In this example, at most a single handle is valid throughout the execution of the loop.
38e41f4b71Sopenharmony_ci```cpp
39e41f4b71Sopenharmony_ci// When N-API is frequently called to create JS objects in the for loop, add handle_scope to release in a timely manner resources that are no longer used.
40e41f4b71Sopenharmony_ci// In the following code, the lifespan of the local variable res ends at the end of each loop. Therefore, a scope is added to release the JS object in time to prevent memory leak.
41e41f4b71Sopenharmony_cifor (int i = 0; i < 1000000; i++) {
42e41f4b71Sopenharmony_ci    napi_handle_scope scope;
43e41f4b71Sopenharmony_ci    napi_status status = napi_open_handle_scope(env, &scope);
44e41f4b71Sopenharmony_ci    if (status != napi_ok) {
45e41f4b71Sopenharmony_ci        break;
46e41f4b71Sopenharmony_ci    }
47e41f4b71Sopenharmony_ci    napi_value result;
48e41f4b71Sopenharmony_ci    status = napi_get_element(env, object, i, &result);
49e41f4b71Sopenharmony_ci    if (status != napi_ok) {
50e41f4b71Sopenharmony_ci        break;
51e41f4b71Sopenharmony_ci    }
52e41f4b71Sopenharmony_ci    // do something with element
53e41f4b71Sopenharmony_ci    status = napi_close_handle_scope(env, scope);
54e41f4b71Sopenharmony_ci    if (status != napi_ok) {
55e41f4b71Sopenharmony_ci        break;
56e41f4b71Sopenharmony_ci    }
57e41f4b71Sopenharmony_ci}
58e41f4b71Sopenharmony_ci```
59e41f4b71Sopenharmony_ciThere are cases where a handle from a scope needs to outlive the scope, for example, in nested loop scenarios. For this purpose, you can use **napi_open_escapable_handle_scope** and **napi_close_escapable_handle_scope** to open and close an escapable scope, where the lifespan of the defined handle is the same as that of the outer scope.
60e41f4b71Sopenharmony_ci
61e41f4b71Sopenharmony_ci### Extending Object Lifespan
62e41f4b71Sopenharmony_ci
63e41f4b71Sopenharmony_ciYou can extend the lifespan of an **napi_value** object, by creating an **napi_ref** reference to a **napi_value** object. All **napi_ref** references, created by calling **napi_create_reference**, must be deleted manually by calling **napi_delete_reference**. Failure to delete a reference may results in memory leak.
64e41f4b71Sopenharmony_ci
65e41f4b71Sopenharmony_ci#### Use Case 1: Saving napi_value
66e41f4b71Sopenharmony_ci
67e41f4b71Sopenharmony_ciUse **napi_define_class** to create a constructor and save it. You can use the saved constructor to call **napi_new_instance** to create an instance. However, if the constructor is saved as a **napi_value**, it will be destructed once it exceeds the scope of the native method. In this case, continuing to use the constructor will result in a wild pointer. To avoid this issue, it is recommended that you:
68e41f4b71Sopenharmony_ci* Save the constructor as an **napi_ref** reference.
69e41f4b71Sopenharmony_ci* Manage the lifespan of the constructor object on your own so that it is not restricted by the scope of the native method.
70e41f4b71Sopenharmony_ci```cpp
71e41f4b71Sopenharmony_ci// 1. Save the constructor as an napi_ref reference.
72e41f4b71Sopenharmony_cistatic napi_value TestDefineClass(napi_env env,
73e41f4b71Sopenharmony_ci                                  napi_callback_info info) {
74e41f4b71Sopenharmony_ci  napi_status status;
75e41f4b71Sopenharmony_ci  napi_value result, return_value;
76e41f4b71Sopenharmony_ci
77e41f4b71Sopenharmony_ci  napi_property_descriptor property_descriptor = {
78e41f4b71Sopenharmony_ci    "TestDefineClass",
79e41f4b71Sopenharmony_ci    NULL,
80e41f4b71Sopenharmony_ci    TestDefineClass,
81e41f4b71Sopenharmony_ci    NULL,
82e41f4b71Sopenharmony_ci    NULL,
83e41f4b71Sopenharmony_ci    NULL,
84e41f4b71Sopenharmony_ci    napi_enumerable | napi_static,
85e41f4b71Sopenharmony_ci    NULL};
86e41f4b71Sopenharmony_ci
87e41f4b71Sopenharmony_ci  NODE_API_CALL(env, napi_create_object(env, &return_value));
88e41f4b71Sopenharmony_ci
89e41f4b71Sopenharmony_ci  status = napi_define_class(NULL,
90e41f4b71Sopenharmony_ci                             "TrackedFunction",
91e41f4b71Sopenharmony_ci                             NAPI_AUTO_LENGTH,
92e41f4b71Sopenharmony_ci                             TestDefineClass,
93e41f4b71Sopenharmony_ci                             NULL,
94e41f4b71Sopenharmony_ci                             1,
95e41f4b71Sopenharmony_ci                             &property_descriptor,
96e41f4b71Sopenharmony_ci                             &result);
97e41f4b71Sopenharmony_ci  SaveConstructor(env, result);
98e41f4b71Sopenharmony_ci  ...
99e41f4b71Sopenharmony_ci}
100e41f4b71Sopenharmony_ci```
101e41f4b71Sopenharmony_ci```cpp
102e41f4b71Sopenharmony_ci// 2. Manage the lifespan of the constructor object on your own.
103e41f4b71Sopenharmony_cinapi_status SaveConstructor(napi_env env, napi_value constructor) {
104e41f4b71Sopenharmony_ci    return napi_create_reference(env, constructor, 1, &g_constructor);
105e41f4b71Sopenharmony_ci};
106e41f4b71Sopenharmony_ci
107e41f4b71Sopenharmony_cinapi_status GetConstructor(napi_env env) {
108e41f4b71Sopenharmony_ci    napi_value constructor;
109e41f4b71Sopenharmony_ci    return napi_get_reference_value(env, g_constructor, &constructor);
110e41f4b71Sopenharmony_ci};
111e41f4b71Sopenharmony_ci```
112e41f4b71Sopenharmony_ci
113e41f4b71Sopenharmony_ci#### Use Case 2: napi_wrap
114e41f4b71Sopenharmony_ci
115e41f4b71Sopenharmony_ciYou can use **napi_wrap** to wrap a native instance in a JavaScript object. When the JavaScript object is garbage-collected, use a callback to free the native instance. In effect, the **napi_wrap** API creates an **napi_ref** reference. You can designate the system to manage the created **napi_ref** reference. Alternatively, you can release the reference manually.
116e41f4b71Sopenharmony_ci```cpp
117e41f4b71Sopenharmony_ci// Usage 1: napi_wrap does not need to receive the created napi_ref reference. The last parameter is nullptr. The created napi_ref reference is managed by the system and does not need to be manually released.
118e41f4b71Sopenharmony_cinapi_wrap(env, jsobject, nativeObject, cb, nullptr, nullptr);
119e41f4b71Sopenharmony_ci
120e41f4b71Sopenharmony_ci// Usage 2: napi_wrap needs to receive the created napi_ref reference. The last parameter is not nullptr. The created napi_ref reference needs to be manually released. Otherwise, memory leak occurs.
121e41f4b71Sopenharmony_cinapi_ref result;
122e41f4b71Sopenharmony_cinapi_wrap(env, jsobject, nativeObject, cb, nullptr, &result);
123e41f4b71Sopenharmony_ci// When the JavaScript object and result are no longer used, call napi_remove_wrap to release the result in a timely manner.
124e41f4b71Sopenharmony_cinapi_value result1;
125e41f4b71Sopenharmony_cinapi_remove_wrap(env, jsobject, result1)
126e41f4b71Sopenharmony_ci```
127e41f4b71Sopenharmony_ci
128e41f4b71Sopenharmony_ci## Cross-Language Invocation Overhead
129e41f4b71Sopenharmony_ci
130e41f4b71Sopenharmony_ci### API Call
131e41f4b71Sopenharmony_ci
132e41f4b71Sopenharmony_ciCross-language invocation is the process where code written in different programming languages calls and interacts with each other in an application. For example, ArkTS invoking C++ is one of the cross-language invocation modes. Using N-API to call functions causes certain overhead, because context switching, parameter transfer, function invoking, and return value processing are required. Currently, there are three scenarios where C++ code is called from ArkTS through N-API: call C++ APIs, listen for C++ APIs , and receive C++ callbacks. Frequent cross-language API calls may detract from service performance. Therefore, properly design the API call frequency.
133e41f4b71Sopenharmony_ci
134e41f4b71Sopenharmony_ci### Value Conversion
135e41f4b71Sopenharmony_ci
136e41f4b71Sopenharmony_ciWhen using N-API to convert data between ArkTS and C++, take note of the following:
137e41f4b71Sopenharmony_ci* Reduce the number of data conversion times: Frequent data conversion may cause performance deterioration. You can process data in batches or use a more efficient data structure to optimize performance.
138e41f4b71Sopenharmony_ci* Avoid unnecessary data replication: During data conversion, use N-API to directly access the original data instead of creating a new data copy.
139e41f4b71Sopenharmony_ci* Use cache: If some data is used in multiple conversions, you can store it in the cache to avoid repeated data conversions. In this way, unnecessary calculations can be reduced, leading to better performance.
140e41f4b71Sopenharmony_ci
141e41f4b71Sopenharmony_ci## Asynchronous Operations
142e41f4b71Sopenharmony_ciI/O- and CPU-intensive tasks must be processed asynchronously. Otherwise, the main thread will be blocked. N-API provides the asynchronous capability, allowing an application to continue executing other tasks instead of being blocked when executing a time-consuming task. When an asynchronous operation is complete, the application receives a notification and can process the operation result.
143e41f4b71Sopenharmony_ci
144e41f4b71Sopenharmony_ci### Example of Asynchronous Processing
145e41f4b71Sopenharmony_ci
146e41f4b71Sopenharmony_ciYou can refer to the following example to implement time-consuming tasks in asynchronous mode. The logic includes the following steps:
147e41f4b71Sopenharmony_ci* Call **napi_create_promise** to create a promise. When a promise is created, a "deferred" object is created and returned alongside the promise.
148e41f4b71Sopenharmony_ci* Execute the time-consuming task and pass the execution result to the promise.
149e41f4b71Sopenharmony_ci* Call **napi_resolve_deferred** or **napi_reject_deferred** to resolve or reject the created promise and release the deferred object.
150e41f4b71Sopenharmony_ci
151e41f4b71Sopenharmony_ci```cpp
152e41f4b71Sopenharmony_ci// Transfer data between executeCB and completeCB.
153e41f4b71Sopenharmony_cistruct AddonData {
154e41f4b71Sopenharmony_ci    napi_async_work asyncWork = nullptr;
155e41f4b71Sopenharmony_ci    napi_deferred deferred = nullptr;
156e41f4b71Sopenharmony_ci    napi_ref callback = nullptr;
157e41f4b71Sopenharmony_ci
158e41f4b71Sopenharmony_ci    double args[2] = {0};
159e41f4b71Sopenharmony_ci    double result = 0;
160e41f4b71Sopenharmony_ci};
161e41f4b71Sopenharmony_ci
162e41f4b71Sopenharmony_ci// 2. Execute the time-consuming task and pass the execution result to the promise.
163e41f4b71Sopenharmony_cistatic void addExecuteCB(napi_env env, void *data) {
164e41f4b71Sopenharmony_ci    AddonData *addonData = (AddonData *)data;
165e41f4b71Sopenharmony_ci    addonData->result = addonData->args[0] + addonData->args[1];
166e41f4b71Sopenharmony_ci};
167e41f4b71Sopenharmony_ci
168e41f4b71Sopenharmony_ci// 3. Call napi_resolve_deferred or napi_reject_deferred to resolve or reject the created promise and release the deferred object.
169e41f4b71Sopenharmony_cistatic void addPromiseCompleteCB(napi_env env, napi_status status, void *data) {
170e41f4b71Sopenharmony_ci    AddonData *addonData = (AddonData *)data;
171e41f4b71Sopenharmony_ci    napi_value result = nullptr;
172e41f4b71Sopenharmony_ci    napi_create_double(env, addonData->result, &result);
173e41f4b71Sopenharmony_ci    napi_resolve_deferred(env, addonData->deferred, result);
174e41f4b71Sopenharmony_ci
175e41f4b71Sopenharmony_ci    if (addonData->callback != nullptr) {
176e41f4b71Sopenharmony_ci        napi_delete_reference(env, addonData->callback);
177e41f4b71Sopenharmony_ci    }
178e41f4b71Sopenharmony_ci
179e41f4b71Sopenharmony_ci    // Delete the asynchronous work.
180e41f4b71Sopenharmony_ci    napi_delete_async_work(env, addonData->asyncWork);
181e41f4b71Sopenharmony_ci    delete addonData;
182e41f4b71Sopenharmony_ci    addonData = nullptr;
183e41f4b71Sopenharmony_ci};
184e41f4b71Sopenharmony_ci
185e41f4b71Sopenharmony_ci// 1. Call napi_create_promise to create a promise. When a promise is created,
186e41f4b71Sopenharmony_ci// a "deferred" object is created and returned alongside the promise.
187e41f4b71Sopenharmony_cistatic napi_value addPromise(napi_env env, napi_callback_info info) {
188e41f4b71Sopenharmony_ci    size_t argc = 2;
189e41f4b71Sopenharmony_ci    napi_value args[2];
190e41f4b71Sopenharmony_ci    napi_value thisArg = nullptr;
191e41f4b71Sopenharmony_ci    napi_get_cb_info(env, info, &argc, args, &thisArg, nullptr);
192e41f4b71Sopenharmony_ci
193e41f4b71Sopenharmony_ci    napi_valuetype valuetype0;
194e41f4b71Sopenharmony_ci    napi_typeof(env, args[0], &valuetype0);
195e41f4b71Sopenharmony_ci    napi_valuetype valuetype1;
196e41f4b71Sopenharmony_ci    napi_typeof(env, args[1], &valuetype1);
197e41f4b71Sopenharmony_ci    if (valuetype0 != napi_number || valuetype1 != napi_number) {
198e41f4b71Sopenharmony_ci        napi_throw_type_error(env, nullptr, "Wrong arguments. 2 numbers expected.");
199e41f4b71Sopenharmony_ci        return NULL;
200e41f4b71Sopenharmony_ci    }
201e41f4b71Sopenharmony_ci
202e41f4b71Sopenharmony_ci    napi_value promise = nullptr;
203e41f4b71Sopenharmony_ci    napi_deferred deferred = nullptr;
204e41f4b71Sopenharmony_ci    napi_create_promise(env, &deferred, &promise);
205e41f4b71Sopenharmony_ci
206e41f4b71Sopenharmony_ci    // Asynchronous work context user data, which is transferred between execute and complete callbacks of the asynchronous work.
207e41f4b71Sopenharmony_ci    auto addonData = new AddonData{
208e41f4b71Sopenharmony_ci        .asyncWork = nullptr,
209e41f4b71Sopenharmony_ci        .deferred = deferred,
210e41f4b71Sopenharmony_ci    };
211e41f4b71Sopenharmony_ci
212e41f4b71Sopenharmony_ci    napi_get_value_double(env, args[0], &addonData->args[0]);
213e41f4b71Sopenharmony_ci    napi_get_value_double(env, args[1], &addonData->args[1]);
214e41f4b71Sopenharmony_ci
215e41f4b71Sopenharmony_ci    // Create an async work. When the creation is successful, the handle to the async work is returned through the last parameter (addonData->asyncWork).
216e41f4b71Sopenharmony_ci    napi_value resourceName = nullptr;
217e41f4b71Sopenharmony_ci    napi_create_string_utf8(env, "addAsyncCallback", NAPI_AUTO_LENGTH, &resourceName);
218e41f4b71Sopenharmony_ci    napi_create_async_work(env, nullptr, resourceName, addExecuteCB, addPromiseCompleteCB, (void *)addonData,
219e41f4b71Sopenharmony_ci                           &addonData->asyncWork);
220e41f4b71Sopenharmony_ci
221e41f4b71Sopenharmony_ci    // Add the newly created async work to the queue for the underlying layer to schedule and execute.
222e41f4b71Sopenharmony_ci    napi_queue_async_work(env, addonData->asyncWork);
223e41f4b71Sopenharmony_ci
224e41f4b71Sopenharmony_ci    return promise;
225e41f4b71Sopenharmony_ci}
226e41f4b71Sopenharmony_ci```
227e41f4b71Sopenharmony_ci
228e41f4b71Sopenharmony_ciAfter the asynchronous operation is complete, the callback is invoked and the result is passed to the **Promise** object. In JavaScript, you can use the **then()** method of the **Promise** object to process the result of an asynchronous operation.
229e41f4b71Sopenharmony_ci
230e41f4b71Sopenharmony_ci```js
231e41f4b71Sopenharmony_ciimport hilog from '@ohos.hilog';
232e41f4b71Sopenharmony_ciimport testNapi from 'libentry.so'
233e41f4b71Sopenharmony_ci
234e41f4b71Sopenharmony_ci@Entry
235e41f4b71Sopenharmony_ci@Component
236e41f4b71Sopenharmony_cistruct TestAdd {
237e41f4b71Sopenharmony_ci  build() {
238e41f4b71Sopenharmony_ci    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
239e41f4b71Sopenharmony_ci      Text("hello world")
240e41f4b71Sopenharmony_ci        .onClick(() => {
241e41f4b71Sopenharmony_ci          let num1 = 2;
242e41f4b71Sopenharmony_ci          let num2 = 3;
243e41f4b71Sopenharmony_ci          testNapi.addPromise(num1, num2).then((result) => {
244e41f4b71Sopenharmony_ci            hilog.info(0x0000, 'testTag', '%{public}d', result);
245e41f4b71Sopenharmony_ci          })
246e41f4b71Sopenharmony_ci        })
247e41f4b71Sopenharmony_ci    }
248e41f4b71Sopenharmony_ci    .width('100%')
249e41f4b71Sopenharmony_ci    .height('100%')
250e41f4b71Sopenharmony_ci  }
251e41f4b71Sopenharmony_ci}
252e41f4b71Sopenharmony_ci```
253e41f4b71Sopenharmony_ci
254e41f4b71Sopenharmony_ci### Prioritizing Asynchronous Tasks
255e41f4b71Sopenharmony_ci
256e41f4b71Sopenharmony_ciFor applications developed using [Function Flow](https://gitee.com/openharmony/resourceschedule_ffrt/blob/master/docs/user_guide.md)), a task-based and data-driven concurrent programming model, you can schedule tasks with the help of the Function Flow Runtime (FFRT). Ark ArkTS runtime provides an extension API, which you can call to invoke FFRT with the QoS information of tasks passed in. The tasks are then scheduled based on their QoS level and system resource usage for a balance between power consumption and performance.
257e41f4b71Sopenharmony_ci
258e41f4b71Sopenharmony_ci* API example: napi_status napi_queue_async_work_with_qos(napi_env env, napi_async_work work, napi_qos_t qos) ()
259e41f4b71Sopenharmony_ci  * **env**: environment for invoking the API.
260e41f4b71Sopenharmony_ci  * **napi_async_work**: asynchronous task.
261e41f4b71Sopenharmony_ci  * **napi_qos_t**: QoS level.
262e41f4b71Sopenharmony_ci
263e41f4b71Sopenharmony_ci* QoS levels:
264e41f4b71Sopenharmony_ci```cpp
265e41f4b71Sopenharmony_citypedef enum {
266e41f4b71Sopenharmony_ci    napi_qos_background = 0,
267e41f4b71Sopenharmony_ci    napi_qos_utility = 1,
268e41f4b71Sopenharmony_ci    napi_qos_default = 2,
269e41f4b71Sopenharmony_ci    napi_qos_user_initiated = 3,
270e41f4b71Sopenharmony_ci} napi_qos_t;
271e41f4b71Sopenharmony_ci```
272e41f4b71Sopenharmony_ci
273e41f4b71Sopenharmony_ci* The N-API layer encapsulates an external API to connect to the **uv_queue_work_with_qos(uv_loop_t* loop, uv_work_t* req, uv_work_cb work_cb, uv_after_work_cb after_work_cb, uv_qos_t qos)** function at the libuv layer.
274e41f4b71Sopenharmony_ci
275e41f4b71Sopenharmony_ci* Compared with the existing API **napi_queue_async_work**, this API adds the QoS level to specify the priority for task scheduling. Example:
276e41f4b71Sopenharmony_ci```cpp
277e41f4b71Sopenharmony_cistatic void PromiseOnExec(napi_env env, void *data) { 
278e41f4b71Sopenharmony_ci    OH_LOG_INFO(LOG_APP, "PromiseOnExec"); 
279e41f4b71Sopenharmony_ci}
280e41f4b71Sopenharmony_ci
281e41f4b71Sopenharmony_cistatic void PromiseOnComplete(napi_env env, napi_status status, void *data) {
282e41f4b71Sopenharmony_ci    int number = *((int *)data);
283e41f4b71Sopenharmony_ci    OH_LOG_INFO(LOG_APP, "PromiseOnComplete number = %{public}d", number);
284e41f4b71Sopenharmony_ci}
285e41f4b71Sopenharmony_ci
286e41f4b71Sopenharmony_cistatic napi_value Test(napi_env env, napi_callback_info info) {
287e41f4b71Sopenharmony_ci    napi_value resourceName = nullptr;
288e41f4b71Sopenharmony_ci    napi_create_string_utf8(env, "TestExample", NAPI_AUTO_LENGTH, &resourceName);
289e41f4b71Sopenharmony_ci    napi_async_work async_work;
290e41f4b71Sopenharmony_ci    int *data = new int(10);
291e41f4b71Sopenharmony_ci    napi_create_async_work(env, nullptr, resourceName, PromiseOnExec, PromiseOnComplete, data, &async_work);
292e41f4b71Sopenharmony_ci    napi_queue_async_work_with_qos(env, async_work, napi_qos_default);
293e41f4b71Sopenharmony_ci    return nullptr;
294e41f4b71Sopenharmony_ci}
295e41f4b71Sopenharmony_ci```
296e41f4b71Sopenharmony_ci
297e41f4b71Sopenharmony_ci## Thread Security
298e41f4b71Sopenharmony_ci
299e41f4b71Sopenharmony_ciIf an application needs to perform a large number of computing or I/O operations, the concurrency mechanism is handy, in that it can make full use of the multi-core CPU to improve the processing efficiency of the application. For example, applications specialized in image processing, video coding, and data analysis may use a concurrency mechanism to improve processing speeds.
300e41f4b71Sopenharmony_ci
301e41f4b71Sopenharmony_ciAlthough N-API itself does not support concurrent operations with multithreading, it does allow for some data interactions in a multi-thread environment, where thread security would be a concern. In a multi-thread environment, you can use **napi_create_threadsafe_function** to create a thread-safe function and then call the function in any thread.
302e41f4b71Sopenharmony_ci
303e41f4b71Sopenharmony_ci*Application scenario*: When there are other threads on the native side and JavaScript functions need to be called based on the completion results of these threads, these threads must communicate with the main thread on the native side so that JavaScript functions can be called in the main thread. Thread-safe functions provide a simplified way to avoid inter-thread communication and to return to the main thread to call JavaScript functions.
304e41f4b71Sopenharmony_ci
305e41f4b71Sopenharmony_ci### How to Use
306e41f4b71Sopenharmony_ci
307e41f4b71Sopenharmony_ci#### Passing Callback from the ArkTS Side
308e41f4b71Sopenharmony_ci```JS
309e41f4b71Sopenharmony_cistruct Index {
310e41f4b71Sopenharmony_ci  @State message: string = 'Hello World'
311e41f4b71Sopenharmony_ci
312e41f4b71Sopenharmony_ci  build() {
313e41f4b71Sopenharmony_ci    Row() {
314e41f4b71Sopenharmony_ci      Column() {
315e41f4b71Sopenharmony_ci        Text(this.message)
316e41f4b71Sopenharmony_ci          .fontSize(50)
317e41f4b71Sopenharmony_ci          .fontWeight(FontWeight.Bold)
318e41f4b71Sopenharmony_ci          .onClick(() => {
319e41f4b71Sopenharmony_ci            testNapi.threadSafeTest((value) => {
320e41f4b71Sopenharmony_ci              hilog.info(0x0000, 'testTag', 'js callback value = ' + value);
321e41f4b71Sopenharmony_ci            })
322e41f4b71Sopenharmony_ci          })
323e41f4b71Sopenharmony_ci      }
324e41f4b71Sopenharmony_ci      .width('100%')
325e41f4b71Sopenharmony_ci    }
326e41f4b71Sopenharmony_ci    .height('100%')
327e41f4b71Sopenharmony_ci  }
328e41f4b71Sopenharmony_ci}
329e41f4b71Sopenharmony_ci```
330e41f4b71Sopenharmony_ci
331e41f4b71Sopenharmony_ci#### Creating Thread-Safe Function in Main Thread on Native Side
332e41f4b71Sopenharmony_ci```cpp
333e41f4b71Sopenharmony_cistatic void CallJs(napi_env env, napi_value js_cb, void *context, void *data) {
334e41f4b71Sopenharmony_ci
335e41f4b71Sopenharmony_ci    std::thread::id this_id = std::this_thread::get_id();
336e41f4b71Sopenharmony_ci    OH_LOG_INFO(LOG_APP, "thread CallJs %{public}d.\n", this_id);
337e41f4b71Sopenharmony_ci    napi_status status;
338e41f4b71Sopenharmony_ci
339e41f4b71Sopenharmony_ci    status = napi_get_reference_value(env, cbObj, &js_cb);
340e41f4b71Sopenharmony_ci
341e41f4b71Sopenharmony_ci    napi_valuetype valueType = napi_undefined;
342e41f4b71Sopenharmony_ci    napi_typeof(env, js_cb, &valueType);
343e41f4b71Sopenharmony_ci    OH_LOG_INFO(LOG_APP, "CallJs js_cb is napi_function: %{public}d", valueType == napi_function);
344e41f4b71Sopenharmony_ci
345e41f4b71Sopenharmony_ci    OH_LOG_INFO(LOG_APP, "CallJs 0");
346e41f4b71Sopenharmony_ci    if (env != NULL) {
347e41f4b71Sopenharmony_ci        napi_value undefined, js_the_prime;
348e41f4b71Sopenharmony_ci        status = napi_create_int32(env, 666, &js_the_prime);
349e41f4b71Sopenharmony_ci        OH_LOG_INFO(LOG_APP, "CallJs 1: %{public}d", status == napi_ok);
350e41f4b71Sopenharmony_ci        status = napi_get_undefined(env, &undefined);
351e41f4b71Sopenharmony_ci        OH_LOG_INFO(LOG_APP, "CallJs 2: %{public}d", status == napi_ok);
352e41f4b71Sopenharmony_ci
353e41f4b71Sopenharmony_ci        napi_value ret;
354e41f4b71Sopenharmony_ci
355e41f4b71Sopenharmony_ci        status = napi_call_function(env, undefined, js_cb, 1, &js_the_prime, &ret);
356e41f4b71Sopenharmony_ci        OH_LOG_INFO(LOG_APP, "CallJs 3: %{public}d", status == napi_ok);
357e41f4b71Sopenharmony_ci    }
358e41f4b71Sopenharmony_ci}
359e41f4b71Sopenharmony_ci
360e41f4b71Sopenharmony_cinapi_threadsafe_function tsfn;
361e41f4b71Sopenharmony_ci
362e41f4b71Sopenharmony_cistatic napi_value ThreadSafeTest(napi_env env, napi_callback_info info) {
363e41f4b71Sopenharmony_ci    size_t argc = 1;
364e41f4b71Sopenharmony_ci    napi_value js_cb, work_name;
365e41f4b71Sopenharmony_ci    napi_status status;
366e41f4b71Sopenharmony_ci
367e41f4b71Sopenharmony_ci    status = napi_get_cb_info(env, info, &argc, &js_cb, NULL, NULL);
368e41f4b71Sopenharmony_ci    OH_LOG_INFO(LOG_APP, "ThreadSafeTest 0: %{public}d", status == napi_ok);
369e41f4b71Sopenharmony_ci
370e41f4b71Sopenharmony_ci    status = napi_create_reference(env, js_cb, 1, &cbObj);
371e41f4b71Sopenharmony_ci    OH_LOG_INFO(LOG_APP, "napi_create_reference of js_cb to cbObj: %{public}d", status == napi_ok);
372e41f4b71Sopenharmony_ci
373e41f4b71Sopenharmony_ci    status =
374e41f4b71Sopenharmony_ci        napi_create_string_utf8(env, "Node-API Thread-safe Call from Async Work Item", NAPI_AUTO_LENGTH, &work_name);
375e41f4b71Sopenharmony_ci    OH_LOG_INFO(LOG_APP, "ThreadSafeTest 1: %{public}d", status == napi_ok);
376e41f4b71Sopenharmony_ci
377e41f4b71Sopenharmony_ci    std::thread::id this_id = std::this_thread::get_id();
378e41f4b71Sopenharmony_ci    OH_LOG_INFO(LOG_APP, "thread ThreadSafeTest %{public}d.\n", this_id);
379e41f4b71Sopenharmony_ci
380e41f4b71Sopenharmony_ci    napi_valuetype valueType = napi_undefined;
381e41f4b71Sopenharmony_ci    napi_typeof(env, js_cb, &valueType);
382e41f4b71Sopenharmony_ci    OH_LOG_INFO(LOG_APP, "ThreadSafeTest js_cb is napi_function: %{public}d", valueType == napi_function);
383e41f4b71Sopenharmony_ci
384e41f4b71Sopenharmony_ci    status = napi_create_threadsafe_function(env, js_cb, NULL, work_name, 0, 1, NULL, NULL, NULL, CallJs, &tsfn);
385e41f4b71Sopenharmony_ci    OH_LOG_INFO(LOG_APP, "ThreadSafeTest 2: %{public}d", status == napi_ok);
386e41f4b71Sopenharmony_ci}
387e41f4b71Sopenharmony_ci```
388e41f4b71Sopenharmony_ci
389e41f4b71Sopenharmony_ci#### Calling Thread-Safe Functions in Other Threads
390e41f4b71Sopenharmony_ci```cpp
391e41f4b71Sopenharmony_cistd::thread t([]() {
392e41f4b71Sopenharmony_ci    std::thread::id this_id = std::this_thread::get_id();
393e41f4b71Sopenharmony_ci    OH_LOG_INFO(LOG_APP, "thread0 %{public}d.\n", this_id);
394e41f4b71Sopenharmony_ci    napi_status status;
395e41f4b71Sopenharmony_ci    status = napi_acquire_threadsafe_function(tsfn);
396e41f4b71Sopenharmony_ci    OH_LOG_INFO(LOG_APP, "thread1 : %{public}d", status == napi_ok);
397e41f4b71Sopenharmony_ci    status = napi_call_threadsafe_function(tsfn, NULL, napi_tsfn_blocking);
398e41f4b71Sopenharmony_ci    OH_LOG_INFO(LOG_APP, "thread2 : %{public}d", status == napi_ok);
399e41f4b71Sopenharmony_ci});
400e41f4b71Sopenharmony_cit.detach();
401e41f4b71Sopenharmony_ci```
402e41f4b71Sopenharmony_ci
403e41f4b71Sopenharmony_ci### Precautions for Using Thread Functions
404e41f4b71Sopenharmony_ciIn a multi-thread environment, avoid using shared data structures and global variables to avoid competition and conflicts. Ensure that threads are synchronized and mutually exclusive to avoid data inconsistency. In addition, pay attention to the following:
405e41f4b71Sopenharmony_ci* The calls to thread-safe functions are asynchronous, and the calls to the JavaScript callbacks are placed in the task queue.
406e41f4b71Sopenharmony_ci* When **napi_threadsafe_function** is called to create a thread-safe function, the **napi_finalize** callback can be provided. When the thread-safe function is about to be destroyed, the **napi_finalize** callback is invoked on the main thread.
407e41f4b71Sopenharmony_ci* The context is given when **napi_create_threadsafe_function** is called and can be obtained from any thread that calls **napi_get_threadsafe_function_context**.
408