1# Asynchronous Task Development Using Node-API
2
3## When to Use
4
5For a time-consuming operation, you can use **napi_create_async_work** to create an asynchronous work object to prevent the main thread from being blocked while ensuring the performance and response of your application. You can use asynchronous work objects in the following scenarios:
6
7- File operations: You can use asynchronous work objects in complex file operations or when a large file needs to be read to prevent the main thread from being blocked.
8
9- Network request: When your application needs to wait for a response to a network request, using an asynchronous worker object can improve its response performance without affecting the main thread.
10
11- Database operation: Using asynchronous work objects in complex database query or write operations can improve the concurrency performance of your application without compromising the running of the main thread.
12
13- Image processing: When large images need to be processed or complex image algorithms need to be executed, asynchronous work objects can ensure normal running of the main thread and improve the real-time performance of your application.
14
15You can use a promise or a callback to implement asynchronous calls. To use a callback, you must pass in the callback.
16
17![](figures/napi_async_work.png)
18
19## Example (Promise)
20
21![](figures/napi_async_work_with_promise.png)
22
231. Use **napi_create_async_work** to create an asynchronous work object, and use **napi_queue_async_work** to add the object to a queue.
24
25   ```cpp
26   struct CallbackData {
27       napi_async_work asyncWork = nullptr;
28       napi_deferred deferred = nullptr;
29       napi_ref callback = nullptr;
30       double args = 0;
31       double result = 0;
32   };
33
34   static napi_value AsyncWork(napi_env env, napi_callback_info info)
35   {
36      size_t argc = 1;
37      napi_value args[1];
38      napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
39
40      napi_value promise = nullptr;
41      napi_deferred deferred = nullptr;
42      napi_create_promise(env, &deferred, &promise);
43
44      auto callbackData = new CallbackData();
45      callbackData->deferred = deferred;
46      napi_get_value_double(env, args[0], &callbackData->args);
47
48      napi_value resourceName = nullptr;
49      napi_create_string_utf8(env, "AsyncCallback", NAPI_AUTO_LENGTH, &resourceName);
50      // Create an asynchronous work object.
51      napi_create_async_work(env, nullptr, resourceName, ExecuteCB, CompleteCB, callbackData, &callbackData->asyncWork);
52      // Add the asynchronous work object to a queue.
53      napi_queue_async_work(env, callbackData->asyncWork);
54
55      return promise;
56   }
57   ```
58
592. Define the first callback of the asynchronous work object. This callback is executed in a worker thread to process specific service logic.
60
61   ```cpp
62   static void ExecuteCB(napi_env env, void *data)
63   {
64       CallbackData *callbackData = reinterpret_cast<CallbackData *>(data);
65       callbackData->result = callbackData->args;
66   }
67   ```
68
693. Define the second callback of the asynchronous work object. This callback is executed in the main thread to return the result to the ArkTS side.
70
71   ```cpp
72   static void CompleteCB(napi_env env, napi_status status, void *data)
73   {
74       CallbackData *callbackData = reinterpret_cast<CallbackData *>(data);
75       napi_value result = nullptr;
76       napi_create_double(env, callbackData->result, &result);
77       if (callbackData->result > 0) {
78           napi_resolve_deferred(env, callbackData->deferred, result);
79       } else {
80           napi_reject_deferred(env, callbackData->deferred, result);
81       }
82
83       napi_delete_async_work(env, callbackData->asyncWork);
84       delete callbackData;
85   }
86   ```
87
884. Initialize the module and call the API of ArkTS.
89
90   ```cpp
91   // Initialize the module.
92   static napi_value Init(napi_env env, napi_value exports)
93   {
94       napi_property_descriptor desc[] = {
95           { "asyncWork", nullptr, AsyncWork, nullptr, nullptr, nullptr, napi_default, nullptr }
96       };
97       napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
98       return exports;
99   }
100    ```
101
102    ```ts
103   // Description of the interface in the .d.ts file.
104   export const asyncWork(data: number): Promise<number>;
105
106   // Call the API of ArkTS.
107   nativeModule.asyncWork(1024).then((result) => {
108       hilog.info(0x0000, 'XXX', 'result is %{public}d', result);
109     });
110   ```
111
112## Example (Callback)
113
114![](figures/napi_async_work_with_callback.png)
115
1161. Use **napi_create_async_work** to create an asynchronous work object, and use **napi_queue_async_work** to add the object to a queue.
117
118   ```cpp
119   struct CallbackData {
120     napi_async_work asyncWork = nullptr;
121     napi_ref callbackRef = nullptr;
122     double args[2] = {0};
123     double result = 0;
124   };
125
126   napi_value AsyncWork(napi_env env, napi_callback_info info)
127   {
128       size_t argc = 3;
129       napi_value args[3];
130       napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
131       auto asyncContext = new CallbackData();
132       // Save the received parameters to callbackData.
133       napi_get_value_double(env, args[0], &asyncContext->args[0]);
134       napi_get_value_double(env, args[1], &asyncContext->args[1]);
135       // Convert the callback to napi_ref to extend its lifecycle to prevent it from being garbage-collected.
136       napi_create_reference(env, args[2], 1, &asyncContext->callbackRef);
137       napi_value resourceName = nullptr;
138       napi_create_string_utf8(env, "asyncWorkCallback", NAPI_AUTO_LENGTH, &resourceName);
139       // Create an asynchronous work object.
140       napi_create_async_work(env, nullptr, resourceName, ExecuteCB, CompleteCB,
141                              asyncContext, &asyncContext->asyncWork);
142       // Add the asynchronous work object to a queue.
143       napi_queue_async_work(env, asyncContext->asyncWork);
144       return nullptr;
145   }
146   ```
147
1482. Define the first callback of the asynchronous work object. This callback is executed in a worker thread to process specific service logic.
149
150   ```cpp
151   static void ExecuteCB(napi_env env, void *data)
152   {
153       CallbackData *callbackData = reinterpret_cast<CallbackData *>(data);
154       callbackData->result = callbackData->args[0] + callbackData->args[1];
155   }
156   ```
157
1583. Define the second callback of the asynchronous work object. This callback is executed in the main thread to return the result to the ArkTS side.
159
160   ```cpp
161   static void CompleteCB(napi_env env, napi_status status, void *data)
162   {
163       CallbackData *callbackData = reinterpret_cast<CallbackData *>(data);
164       napi_value callbackArg[1] = {nullptr};
165       napi_create_double(env, callbackData->result, &callbackArg[0]);
166       napi_value callback = nullptr;
167       napi_get_reference_value(env, callbackData->callbackRef, &callback);
168       // Execute the callback.
169       napi_value result;
170       napi_value undefined;
171       napi_get_undefined(env, &undefined);
172       napi_call_function(env, undefined, callback, 1, callbackArg, &result);
173       // Delete the napi_ref object and asynchronous work object.
174       napi_delete_reference(env, callbackData->callbackRef);
175       napi_delete_async_work(env, callbackData->asyncWork);
176       delete callbackData;
177   }
178   ```
179
1804. Initialize the module and call the API of ArkTS.
181
182   ```cpp
183   // Initialize the module.
184   static napi_value Init(napi_env env, napi_value exports)
185   {
186       napi_property_descriptor desc[] = {
187           { "asyncWork", nullptr, AsyncWork, nullptr, nullptr, nullptr, napi_default, nullptr }
188       };
189       napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
190       return exports;
191   }
192   ```
193
194   ```ts
195   // Description of the interface in the .d.ts file.
196   export const asyncWork(arg1: number, arg2: number,
197     callback: (result: number) => void): void;
198
199   // Call the API of ArkTS.
200   let num1: number = 123;
201   let num2: number = 456;
202   nativeModule.asyncWork(num1, num2, (result) => {
203     hilog.info(0x0000, 'XXX', 'result is %{public}d', result);
204   });
205   ```
206