1e41f4b71Sopenharmony_ci# Implementing Asynchronous Operations Using Node-API
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci## Introduction
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ciNode-API provides APIs for implementing asynchronous operations for time-consuming tasks, such as downloading data from network or reading a large file. Different from synchronous operations, asynchronous operations are executed in the background without blocking the main thread. When an asynchronous operation is complete, it will be added to the task queue and executed when the main thread is idle.
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ci## Basic Concepts
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ci**Promise** is an object used to handle asynchronous operations in ArkTS. It has three states: **pending**, **fulfilled**, and **rejected**. The initial state is **pending**, which can be changed to **fulfilled** by **resolve()** and to **rejected** by **reject()**. Once the state is **fulfilled** or **rejected**, the promise state cannot be changed. Read on the following to learn basic concepts related to **Promise**:
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ci- Synchronous: Code is executed line by line in sequence. Each line of code is executed after the previous line of code is executed. During synchronous execution, if an operation takes a long time, the execution of the entire application will be blocked until the operation is complete.
12e41f4b71Sopenharmony_ci- Asynchronous: Tasks can be executed concurrently without waiting for the end of the previous task. In ArkTS, common asynchronous operations apply for timers, event listening, and network requests. Instead of blocking subsequent tasks, the asynchronous task uses a callback or promise to process its result.
13e41f4b71Sopenharmony_ci- **Promise**: an ArkTS object used to handle asynchronous operations. Generally, it is exposed externally by using **then()**, **catch()**, or **finally()** to custom logic.
14e41f4b71Sopenharmony_ci- **deferred**: a utility object associated with the **Promise** object to set **resolve()** and **reject()** of **Promise**. It is used internally to maintain the state of the asynchronous model and set the **resolve()** and **reject()** callbacks.
15e41f4b71Sopenharmony_ci- **resolve**: a function used to change the promise state from **pending** to **fulfilled**. The parameters passed to **resolve()** can be obtained from **then()** of the **Promise** object.
16e41f4b71Sopenharmony_ci- **reject**: a function used to change the promise state from **pending** to **rejected**. The parameters passed to **reject()** can be obtained from **catch()** of the **Promise** object.
17e41f4b71Sopenharmony_ci
18e41f4b71Sopenharmony_ci**Promise** allows multiple callbacks to be called in a chain, providing better code readability and a better way to deal with asynchronous operations. The APIs provided by the Node-API module help you flexibly process ArkTS asynchronous operations in C/C++.
19e41f4b71Sopenharmony_ci
20e41f4b71Sopenharmony_ci## Available APIs
21e41f4b71Sopenharmony_ci
22e41f4b71Sopenharmony_ciThe following table lists the APIs for implementing asynchronous operations using ArkTS promises.   
23e41f4b71Sopenharmony_ci| API| Description|
24e41f4b71Sopenharmony_ci| -------- | -------- |
25e41f4b71Sopenharmony_ci| napi_is_promise | Checks whether a **napi_value** is a **Promise** object.|
26e41f4b71Sopenharmony_ci| napi_create_promise | Creates a **Promise** object.|
27e41f4b71Sopenharmony_ci| napi_resolve_deferred | Resolves a promise by using the **deferred** object associated with it.|
28e41f4b71Sopenharmony_ci| napi_reject_deferred | Rejects a promise by using the **deferred** object associated with it|
29e41f4b71Sopenharmony_ci
30e41f4b71Sopenharmony_ci## Example
31e41f4b71Sopenharmony_ci
32e41f4b71Sopenharmony_ciIf you are just starting out with Node-API, see [Node-API Development Process](use-napi-process.md). The following demonstrates only the C++ and ArkTS code related to promises.
33e41f4b71Sopenharmony_ci
34e41f4b71Sopenharmony_ci### napi_is_promise
35e41f4b71Sopenharmony_ci
36e41f4b71Sopenharmony_ciUse **napi_is_promise** to check whether the given **napi_value** is a **Promise** object.
37e41f4b71Sopenharmony_ci
38e41f4b71Sopenharmony_ciCPP code:
39e41f4b71Sopenharmony_ci
40e41f4b71Sopenharmony_ci```cpp
41e41f4b71Sopenharmony_ci#include "napi/native_api.h"
42e41f4b71Sopenharmony_ci
43e41f4b71Sopenharmony_cistatic napi_value IsPromise(napi_env env, napi_callback_info info) 
44e41f4b71Sopenharmony_ci{
45e41f4b71Sopenharmony_ci    napi_value argv[1] = {nullptr};
46e41f4b71Sopenharmony_ci    size_t argc = 1;
47e41f4b71Sopenharmony_ci    napi_status status;
48e41f4b71Sopenharmony_ci    // Obtain the parameters passed in.
49e41f4b71Sopenharmony_ci    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
50e41f4b71Sopenharmony_ci    bool isPromise = false;
51e41f4b71Sopenharmony_ci    // Check whether the given parameter is a Promise object and save the result in the isPromise variable.
52e41f4b71Sopenharmony_ci    status = napi_is_promise(env, argv[0], &isPromise);
53e41f4b71Sopenharmony_ci    if (status != napi_ok) {
54e41f4b71Sopenharmony_ci        napi_throw_error(env, nullptr, "Node-API napi_is_promise failed");
55e41f4b71Sopenharmony_ci        return nullptr;
56e41f4b71Sopenharmony_ci    }
57e41f4b71Sopenharmony_ci    napi_value result = nullptr;
58e41f4b71Sopenharmony_ci    // Convert the value of isPromise to the type specified by napi_value, and return it.
59e41f4b71Sopenharmony_ci    napi_get_boolean(env, isPromise, &result);
60e41f4b71Sopenharmony_ci    return result;
61e41f4b71Sopenharmony_ci}
62e41f4b71Sopenharmony_ci```
63e41f4b71Sopenharmony_ci
64e41f4b71Sopenharmony_ciAPI declaration:
65e41f4b71Sopenharmony_ci
66e41f4b71Sopenharmony_ci```ts
67e41f4b71Sopenharmony_ci// index.d.ts
68e41f4b71Sopenharmony_ciexport const isPromise: <T>(value: T) => boolean;
69e41f4b71Sopenharmony_ci```
70e41f4b71Sopenharmony_ci
71e41f4b71Sopenharmony_ciArkTS code:
72e41f4b71Sopenharmony_ci
73e41f4b71Sopenharmony_ci```ts
74e41f4b71Sopenharmony_ciimport hilog from '@ohos.hilog'
75e41f4b71Sopenharmony_ciimport testNapi from 'libentry.so'
76e41f4b71Sopenharmony_ci
77e41f4b71Sopenharmony_cilet value = Promise.resolve();
78e41f4b71Sopenharmony_ci// Return true if the object passed in is a promise; return false otherwise.
79e41f4b71Sopenharmony_cihilog.info(0x0000, 'Node-API', 'napi_is_promise %{public}s', testNapi.isPromise(value));
80e41f4b71Sopenharmony_cihilog.info(0x0000, 'Node-API', 'napi_is_promise string %{public}s', testNapi.isPromise(''));
81e41f4b71Sopenharmony_ci```
82e41f4b71Sopenharmony_ci
83e41f4b71Sopenharmony_ci### napi_create_promise
84e41f4b71Sopenharmony_ci
85e41f4b71Sopenharmony_ciUse **napi_create_promise** to create a **Promise** object.
86e41f4b71Sopenharmony_ci
87e41f4b71Sopenharmony_ci### napi_resolve_deferred & napi_reject_deferred
88e41f4b71Sopenharmony_ci
89e41f4b71Sopenharmony_ciUse **napi_resolve_deferred** to change the promise state from **pending** to **fulfilled**, and use **napi_reject_deferred** to change the promise state from **pending** to **rejected**.
90e41f4b71Sopenharmony_ci
91e41f4b71Sopenharmony_ciCPP code:
92e41f4b71Sopenharmony_ci
93e41f4b71Sopenharmony_ci```cpp
94e41f4b71Sopenharmony_ci#include "napi/native_api.h"
95e41f4b71Sopenharmony_ci
96e41f4b71Sopenharmony_cistatic napi_value CreatePromise(napi_env env, napi_callback_info info)
97e41f4b71Sopenharmony_ci{
98e41f4b71Sopenharmony_ci    // The deferred object is used to delay the execution of a function for a certain period of time.
99e41f4b71Sopenharmony_ci    napi_deferred deferred = nullptr;
100e41f4b71Sopenharmony_ci    napi_value promise = nullptr;
101e41f4b71Sopenharmony_ci    // Create a Promise object.
102e41f4b71Sopenharmony_ci    napi_status status = napi_create_promise(env, &deferred, &promise);
103e41f4b71Sopenharmony_ci    if (status != napi_ok) {
104e41f4b71Sopenharmony_ci        napi_throw_error(env, nullptr, "Create promise failed");
105e41f4b71Sopenharmony_ci        return nullptr;
106e41f4b71Sopenharmony_ci    }
107e41f4b71Sopenharmony_ci    //Call napi_is_promise to check whether the object created by napi_create_promise is a Promise object.
108e41f4b71Sopenharmony_ci    bool isPromise = false;
109e41f4b71Sopenharmony_ci    napi_value returnIsPromise = nullptr;
110e41f4b71Sopenharmony_ci    napi_is_promise(env, promise, &isPromise);
111e41f4b71Sopenharmony_ci    // Convert the Boolean value to napi_value and return it.
112e41f4b71Sopenharmony_ci    napi_get_boolean(env, isPromise, &returnIsPromise);
113e41f4b71Sopenharmony_ci    return returnIsPromise;
114e41f4b71Sopenharmony_ci}
115e41f4b71Sopenharmony_ci
116e41f4b71Sopenharmony_cistatic napi_value ResolveRejectDeferred(napi_env env, napi_callback_info info) 
117e41f4b71Sopenharmony_ci{
118e41f4b71Sopenharmony_ci    // Obtain and parse parameters.
119e41f4b71Sopenharmony_ci    size_t argc = 3;
120e41f4b71Sopenharmony_ci    napi_value args[3] = {nullptr};
121e41f4b71Sopenharmony_ci    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
122e41f4b71Sopenharmony_ci    // The first parameter is the data to be passed to Resolve(), the second parameter is the data to be passed to reject(), and the third parameter is the Promise state.
123e41f4b71Sopenharmony_ci    bool status;
124e41f4b71Sopenharmony_ci    napi_get_value_bool(env, args[2], &status);
125e41f4b71Sopenharmony_ci    // Create a Promise object.
126e41f4b71Sopenharmony_ci    napi_deferred deferred = nullptr;
127e41f4b71Sopenharmony_ci    napi_value promise = nullptr;
128e41f4b71Sopenharmony_ci    napi_status createStatus = napi_create_promise(env, &deferred, &promise);
129e41f4b71Sopenharmony_ci    if (createStatus != napi_ok) {
130e41f4b71Sopenharmony_ci        napi_throw_error(env, nullptr, "Create promise failed");
131e41f4b71Sopenharmony_ci        return nullptr;
132e41f4b71Sopenharmony_ci    }
133e41f4b71Sopenharmony_ci    // Set the promise state based on the third parameter.
134e41f4b71Sopenharmony_ci    if (status) {
135e41f4b71Sopenharmony_ci        napi_resolve_deferred(env, deferred, args[0]);
136e41f4b71Sopenharmony_ci    } else {
137e41f4b71Sopenharmony_ci        napi_reject_deferred(env, deferred, args[1]);
138e41f4b71Sopenharmony_ci    }
139e41f4b71Sopenharmony_ci    // Return the Promise object with the state set.
140e41f4b71Sopenharmony_ci    return promise;
141e41f4b71Sopenharmony_ci}
142e41f4b71Sopenharmony_ci```
143e41f4b71Sopenharmony_ci
144e41f4b71Sopenharmony_ciAPI declaration:
145e41f4b71Sopenharmony_ci
146e41f4b71Sopenharmony_ci```ts
147e41f4b71Sopenharmony_ci// index.d.ts
148e41f4b71Sopenharmony_ciexport const createPromise: () => boolean | void;
149e41f4b71Sopenharmony_ciexport const resolveRejectDeferred: (resolve: string, reject: string, status: boolean) => Promise<string> | void;
150e41f4b71Sopenharmony_ci```
151e41f4b71Sopenharmony_ci
152e41f4b71Sopenharmony_ciArkTS code:
153e41f4b71Sopenharmony_ci
154e41f4b71Sopenharmony_ci```ts
155e41f4b71Sopenharmony_ciimport hilog from '@ohos.hilog'
156e41f4b71Sopenharmony_ciimport testNapi from 'libentry.so'
157e41f4b71Sopenharmony_ci
158e41f4b71Sopenharmony_ci// Create a promise. Return true if the operation is successful, and return false otherwise.
159e41f4b71Sopenharmony_cihilog.info(0x0000, 'Node-API', 'napi_create_promise %{public}s', testNapi.createPromise());
160e41f4b71Sopenharmony_ci// Call resolveRejectDeferred to resolve or reject the promise and set the promise state.
161e41f4b71Sopenharmony_ci// Resolve the promise. The return value is passed to the then function.
162e41f4b71Sopenharmony_cilet promiseSuccess: Promise<string> = testNapi.resolveRejectDeferred('success', 'fail', true) as Promise<string>;
163e41f4b71Sopenharmony_cipromiseSuccess.then((res) => {
164e41f4b71Sopenharmony_ci  hilog.info(0x0000, 'Node-API', 'get_resolve_deferred resolve %{public}s', res)
165e41f4b71Sopenharmony_ci}).catch((err: Error) => {
166e41f4b71Sopenharmony_ci  hilog.info(0x0000, 'Node-API', 'get_resolve_deferred reject %{public}s', err)
167e41f4b71Sopenharmony_ci})
168e41f4b71Sopenharmony_ci// Reject the promise. The return value is passed to the catch function.
169e41f4b71Sopenharmony_cilet promiseFail: Promise<string> = testNapi.resolveRejectDeferred('success', 'fail', false) as Promise<string>;
170e41f4b71Sopenharmony_cipromiseFail.then((res) => {
171e41f4b71Sopenharmony_ci  hilog.info(0x0000, 'Node-API', 'get_resolve_deferred resolve %{public}s', res)
172e41f4b71Sopenharmony_ci}).catch((err: Error) => {
173e41f4b71Sopenharmony_ci  hilog.info(0x0000, 'Node-API', 'get_resolve_deferred reject %{public}s', err)
174e41f4b71Sopenharmony_ci})
175e41f4b71Sopenharmony_ci```
176e41f4b71Sopenharmony_ci
177e41f4b71Sopenharmony_ciTo print logs in the native CPP, add the following information to the **CMakeLists.txt** file and add the header file by using **#include "hilog/log.h"**.
178e41f4b71Sopenharmony_ci
179e41f4b71Sopenharmony_ci```text
180e41f4b71Sopenharmony_ci// CMakeLists.txt
181e41f4b71Sopenharmony_ciadd_definitions( "-DLOG_DOMAIN=0xd0d0" )
182e41f4b71Sopenharmony_ciadd_definitions( "-DLOG_TAG=\"testTag\"" )
183e41f4b71Sopenharmony_citarget_link_libraries(entry PUBLIC libhilog_ndk.z.so)
184e41f4b71Sopenharmony_ci```
185