1# Asynchronous Task Development Using Node-API 2 3## When to Use 4 5For time-consuming operations, you can use [napi_create_async_work](../reference/native-lib/napi.md#napi_create_async_work) to create an asynchronous work object to prevent the ArkTS thread where env exists 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 ArkTS thread where env exists 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 15The **napi_queue_async_work** API uses the **uv_queue_work** capability at the bottom layer and manages the lifecycle of **napi_value** in the callback. 16 17You can use a promise or a callback to implement asynchronous calls. The following are sample codes for the two methods: 18 19 20 21## Example (Promise) 22 23 24 251. Call **napi_create_async_work** to create an asynchronous work object, and call **napi_queue_async_work** to add the object to a queue. 26 27 ```cpp 28 // Data context provided by the caller. The data is transferred to the execute and complete functions. 29 struct CallbackData { 30 napi_async_work asyncWork = nullptr; 31 napi_deferred deferred = nullptr; 32 napi_ref callback = nullptr; 33 double args = 0; 34 double result = 0; 35 }; 36 37 static napi_value AsyncWork(napi_env env, napi_callback_info info) 38 { 39 size_t argc = 1; 40 napi_value args[1]; 41 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 42 43 napi_value promise = nullptr; 44 napi_deferred deferred = nullptr; 45 napi_create_promise(env, &deferred, &promise); 46 47 auto callbackData = new CallbackData(); 48 callbackData->deferred = deferred; 49 napi_get_value_double(env, args[0], &callbackData->args); 50 51 napi_value resourceName = nullptr; 52 napi_create_string_utf8(env, "AsyncCallback", NAPI_AUTO_LENGTH, &resourceName); 53 // Create an asynchronous work object. 54 napi_create_async_work(env, nullptr, resourceName, ExecuteCB, CompleteCB, callbackData, &callbackData->asyncWork); 55 // Add the asynchronous work object to a queue. 56 napi_queue_async_work(env, callbackData->asyncWork); 57 58 return promise; 59 } 60 ``` 61 622. Define the first callback of the asynchronous work object. This callback is executed in a worker thread to process specific service logic. 63 64 ```cpp 65 static void ExecuteCB(napi_env env, void *data) 66 { 67 CallbackData *callbackData = reinterpret_cast<CallbackData *>(data); 68 callbackData->result = callbackData->args; 69 } 70 ``` 71 723. 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. 73 74 ```cpp 75 static void CompleteCB(napi_env env, napi_status status, void *data) 76 { 77 CallbackData *callbackData = reinterpret_cast<CallbackData *>(data); 78 napi_value result = nullptr; 79 napi_create_double(env, callbackData->result, &result); 80 if (callbackData->result > 0) { 81 napi_resolve_deferred(env, callbackData->deferred, result); 82 } else { 83 napi_reject_deferred(env, callbackData->deferred, result); 84 } 85 86 napi_delete_async_work(env, callbackData->asyncWork); 87 delete callbackData; 88 } 89 ``` 90 914. Initialize the module and call the API of ArkTS. 92 93 ```cpp 94 // Initialize the module. 95 static napi_value Init(napi_env env, napi_value exports) 96 { 97 napi_property_descriptor desc[] = { 98 { "asyncWork", nullptr, AsyncWork, nullptr, nullptr, nullptr, napi_default, nullptr } 99 }; 100 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); 101 return exports; 102 } 103 ``` 104 105 ```ts 106 // Description of the interface in the .d.ts file. 107 export const asyncWork: (data: number) => Promise<number>; 108 109 // Call the API of ArkTS. 110 nativeModule.asyncWork(1024).then((result) => { 111 hilog.info(0x0000, 'XXX', 'result is %{public}d', result); 112 }); 113 ``` 114 Result: **result is 1024** 115 116## Example (Callback) 117 118 119 1201. Call **napi_create_async_work** to create an asynchronous work object, and call **napi_queue_async_work** to add the object to a queue. 121 122 ```cpp 123 static constexpr int INT_ARG_2 = 2; // Input parameter index. 124 125 // Data context provided by the caller. The data is transferred to the execute and complete functions. 126 struct CallbackData { 127 napi_async_work asyncWork = nullptr; 128 napi_ref callbackRef = nullptr; 129 double args[2] = {0}; 130 double result = 0; 131 }; 132 133 napi_value AsyncWork(napi_env env, napi_callback_info info) 134 { 135 size_t argc = 3; 136 napi_value args[3]; 137 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 138 auto asyncContext = new CallbackData(); 139 // Save the received parameters to callbackData. 140 napi_get_value_double(env, args[0], &asyncContext->args[0]); 141 napi_get_value_double(env, args[1], &asyncContext->args[1]); 142 // Convert the callback to napi_ref to extend its lifecycle to prevent it from being garbage-collected. 143 napi_create_reference(env, args[INT_ARG_2], 1, &asyncContext->callbackRef); 144 napi_value resourceName = nullptr; 145 napi_create_string_utf8(env, "asyncWorkCallback", NAPI_AUTO_LENGTH, &resourceName); 146 // Create an asynchronous work object. 147 napi_create_async_work(env, nullptr, resourceName, ExecuteCB, CompleteCB, 148 asyncContext, &asyncContext->asyncWork); 149 // Add the asynchronous work object to a queue. 150 napi_queue_async_work(env, asyncContext->asyncWork); 151 return nullptr; 152 } 153 ``` 154 1552. Define the first callback of the asynchronous work object. This callback is executed in a worker thread to process specific service logic. 156 157 ```cpp 158 static void ExecuteCB(napi_env env, void *data) 159 { 160 CallbackData *callbackData = reinterpret_cast<CallbackData *>(data); 161 callbackData->result = callbackData->args[0] + callbackData->args[1]; 162 } 163 ``` 164 1653. 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. 166 167 ```cpp 168 static void CompleteCB(napi_env env, napi_status status, void *data) 169 { 170 CallbackData *callbackData = reinterpret_cast<CallbackData *>(data); 171 napi_value callbackArg[1] = {nullptr}; 172 napi_create_double(env, callbackData->result, &callbackArg[0]); 173 napi_value callback = nullptr; 174 napi_get_reference_value(env, callbackData->callbackRef, &callback); 175 // Execute the callback. 176 napi_value result; 177 napi_value undefined; 178 napi_get_undefined(env, &undefined); 179 napi_call_function(env, undefined, callback, 1, callbackArg, &result); 180 // Delete the napi_ref object and asynchronous work object. 181 napi_delete_reference(env, callbackData->callbackRef); 182 napi_delete_async_work(env, callbackData->asyncWork); 183 delete callbackData; 184 } 185 ``` 186 1874. Initialize the module and call the API of ArkTS. 188 189 ```cpp 190 // Initialize the module. 191 static napi_value Init(napi_env env, napi_value exports) 192 { 193 napi_property_descriptor desc[] = { 194 { "asyncWork", nullptr, AsyncWork, nullptr, nullptr, nullptr, napi_default, nullptr } 195 }; 196 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); 197 return exports; 198 } 199 ``` 200 201 ```ts 202 // Description of the interface in the .d.ts file. 203 export const asyncWork: (arg1: number, arg2: number, callback: (result: number) => void) => void; 204 205 // Call the API of ArkTS. 206 let num1: number = 123; 207 let num2: number = 456; 208 nativeModule.asyncWork(num1, num2, (result) => { 209 hilog.info(0x0000, 'XXX', 'result is %{public}d', result); 210 }); 211 ``` 212 213## NOTE 214- When the **napi_cancel_async_work** API is called, **napi_ok** is returned regardless of whether the underlying UV fails. If the task fails to be canceled due to the underlying UV, the corresponding error value is transferred to **status** in the complete callback. You need to perform the corresponding operation based on the value of **status**. 215- It is recommended that the asynchronous work item of Node-API (**napi_async_work**) be used only once. After **napi_queue_async_work** is called, you should release it through **napi_delete_async_work** during or after the execution of the **complete** callback. The same **napi_async_work** can be released only once. Repeated release attempts will cause undefined behavior. 216