• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 使用Node-API接口进行异步任务开发
2
3## 场景介绍
4
5napi_create_async_work是Node-API接口之一,用于创建一个异步工作对象。可以在需要执行耗时操作的场景中使用,以避免阻塞主线程,确保应用程序的性能和响应性能。例如以下场景:
6
7- 文件操作:读取大型文件或执行复杂的文件操作时,可以使用异步工作对象来避免阻塞主线程。
8
9- 网络请求:当需要进行网络请求并等待响应时,使用异步工作对象可以确保主线程不被阻塞,从而提高应用程序的响应性能。
10
11- 数据库操作:当需要执行复杂的数据库查询或写入操作时,使用异步工作对象可以确保主线程不被阻塞,从而提高应用程序的并发性能。
12
13- 图像处理:当需要对大型图像进行处理或执行复杂的图像算法时,使用异步工作对象可以确保主线程不被阻塞,从而提高应用程序的实时性能。
14
15异步调用支持callback方式和Promise方式,使用哪种方式由应用开发者决定,通过是否传递callback函数进行区分。
16
17![NAPI 异步任务线程](figures/napi_async_work.png)
18
19## 使用Promise方式示例
20
21![NAPI Promise异步流程](figures/napi_async_work_with_promise.png)
22
231. 使用napi_create_async_work创建异步任务,并使用napi_queue_async_work将异步任务加入队列,等待执行。
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      // 创建异步任务
51      napi_create_async_work(env, nullptr, resourceName, ExecuteCB, CompleteCB, callbackData, &callbackData->asyncWork);
52      // 将异步任务加入队列
53      napi_queue_async_work(env, callbackData->asyncWork);
54
55      return promise;
56   }
57   ```
58
592. 定义异步任务的第一个回调函数,该函数在工作线程中执行,处理具体的业务逻辑。
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. 定义异步任务的第二个回调函数,该函数在主线程执行,将结果传递给ArkTS侧。
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. 模块初始化以及ArkTS侧调用接口。
89
90   ```cpp
91   // 模块初始化
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   // 接口对应的.d.ts描述
104   export const asyncWork: (data: number) => Promise<number>;
105
106   // ArkTS侧调用接口
107   nativeModule.asyncWork(1024).then((result) => {
108       hilog.info(0x0000, 'XXX', 'result is %{public}d', result);
109     });
110   ```
111
112## 使用callback方式示例
113
114![NAPI Callback异步流程](figures/napi_async_work_with_callback.png)
115
1161. 使用napi_create_async_work创建异步任务,并使用napi_queue_async_work将异步任务加入队列,等待执行。
117
118   ```cpp
119   static constexpr int INT_ARG_2 = 2; // 入参索引
120
121   struct CallbackData {
122     napi_async_work asyncWork = nullptr;
123     napi_ref callbackRef = nullptr;
124     double args[2] = {0};
125     double result = 0;
126   };
127
128   napi_value AsyncWork(napi_env env, napi_callback_info info)
129   {
130       size_t argc = 3;
131       napi_value args[3];
132       napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
133       auto asyncContext = new CallbackData();
134       // 将接收到的参数保存到callbackData
135       napi_get_value_double(env, args[0], &asyncContext->args[0]);
136       napi_get_value_double(env, args[1], &asyncContext->args[1]);
137       // 将传入的callback转换为napi_ref延长其生命周期,防止被GC掉
138       napi_create_reference(env, args[INT_ARG_2], 1, &asyncContext->callbackRef);
139       napi_value resourceName = nullptr;
140       napi_create_string_utf8(env, "asyncWorkCallback", NAPI_AUTO_LENGTH, &resourceName);
141       // 创建异步任务
142       napi_create_async_work(env, nullptr, resourceName, ExecuteCB, CompleteCB,
143                              asyncContext, &asyncContext->asyncWork);
144       // 将异步任务加入队列
145       napi_queue_async_work(env, asyncContext->asyncWork);
146       return nullptr;
147   }
148   ```
149
1502. 定义异步任务的第一个回调函数,该函数在工作线程中执行,处理具体的业务逻辑。
151
152   ```cpp
153   static void ExecuteCB(napi_env env, void *data)
154   {
155       CallbackData *callbackData = reinterpret_cast<CallbackData *>(data);
156       callbackData->result = callbackData->args[0] + callbackData->args[1];
157   }
158   ```
159
1603. 定义异步任务的第二个回调函数,该函数在主线程执行,将结果传递给ArkTS侧。
161
162   ```cpp
163   static void CompleteCB(napi_env env, napi_status status, void *data)
164   {
165       CallbackData *callbackData = reinterpret_cast<CallbackData *>(data);
166       napi_value callbackArg[1] = {nullptr};
167       napi_create_double(env, callbackData->result, &callbackArg[0]);
168       napi_value callback = nullptr;
169       napi_get_reference_value(env, callbackData->callbackRef, &callback);
170       // 执行回调函数
171       napi_value result;
172       napi_value undefined;
173       napi_get_undefined(env, &undefined);
174       napi_call_function(env, undefined, callback, 1, callbackArg, &result);
175       // 删除napi_ref对象以及异步任务
176       napi_delete_reference(env, callbackData->callbackRef);
177       napi_delete_async_work(env, callbackData->asyncWork);
178       delete callbackData;
179   }
180   ```
181
1824. 模块初始化以及ArkTS侧调用接口。
183
184   ```cpp
185   // 模块初始化
186   static napi_value Init(napi_env env, napi_value exports)
187   {
188       napi_property_descriptor desc[] = {
189           { "asyncWork", nullptr, AsyncWork, nullptr, nullptr, nullptr, napi_default, nullptr }
190       };
191       napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
192       return exports;
193   }
194   ```
195
196   ```ts
197   // 接口对应的.d.ts描述
198   export const asyncWork: (arg1: number, arg2: number, callback: (result: number) => void) => void;
199
200   // ArkTS侧调用接口
201   let num1: number = 123;
202   let num2: number = 456;
203   nativeModule.asyncWork(num1, num2, (result) => {
204     hilog.info(0x0000, 'XXX', 'result is %{public}d', result);
205   });
206   ```
207