• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Worker
2
3Worker primarily provides a multithreaded runtime environment for applications, allowing them to separate from the host thread during execution. This enables scripts to run in background threads for time-consuming operations, significantly reducing the likelihood of blocking the host thread during compute-intensive or high-latency tasks. For details about the APIs and their usage, see [Worker](../reference/apis-arkts/js-apis-worker.md).
4
5
6## Worker Operating Mechanism
7
8**Figure 1** Worker operating mechanism
9
10![worker](figures/worker.png)
11
12When creating a Worker, the thread that initiates it is referred to as the host thread (not necessarily the main thread, as worker threads can also create child Workers). The Worker itself runs in its own thread, known as a Worker thread or actor thread. Each Worker thread operates independently, with its own infrastructure, objects, and code segments, which incurs some memory overhead for each Worker. Therefore, the number of Worker threads should be limited. The Worker thread communicates with the host thread by means of message exchange. They use the serialization technique to exchange commands and data.
13
14
15## Precautions for Worker
16
17- A Worker can be created manually or automatically. In manual creation mode, you must also synchronize the related configuration. For details, see [Precautions for Creating a Worker](#precautions-for-creating-a-worker).
18- When using Worker capabilities, the URL of the Worker thread file passed in the constructor varies by API version. For specifics, see [Precautions for File URLs](#precautions-for-file-urls).
19- After a Worker is created, its lifecycle must be managed manually. A maximum of 64 Worker threads can run simultaneously, and the total number cannot exceed 80, including those created with [napi_create_ark_runtime](../reference/native-lib/napi.md#napi_create_ark_runtime). For details, see [Precautions for Lifecycle Management](#precautions-for-lifecycle-management).
20- The context objects in different threads are different. Therefore, Worker threads can use only thread-safe libraries. For example, non-thread-safe UI-related libraries cannot be used.
21- A maximum of 16 MB data can be serialized.
22- When using the Worker module, register the **onerror** callback in the host thread. Otherwise, JS crash occurs when the Worker thread is abnormal.
23- Worker thread files cannot be used across HAPs.
24- Before referencing a HAR or HSP, configure the dependency on the HAR or HSP. For details, see [Referencing a Shared Package](https://developer.huawei.com/consumer/en/doc/harmonyos-guides-V5/ide-har-import-V5).
25- [AppStorage](../quick-start/arkts-appstorage.md) cannot be used in Worker threads.
26
27### Precautions for Creating a Worker
28
29The Worker thread file must be placed in the ***{moduleName}*/src/main/ets/** directory to be included in the application package. There are two ways to create Worker thread directories and files: manually and automatically.
30
31- Manual creation: Manually create the directory and file, and configure the related field in **build-profile.json5** so that the Worker thread file can be packed into the application package.
32
33  Stage model:
34
35  ```json
36  "buildOption": {
37    "sourceOption": {
38      "workers": [
39        "./src/main/ets/workers/worker.ets"
40      ]
41    }
42  }
43  ```
44
45  FA model:
46
47  ```json
48  "buildOption": {
49    "sourceOption": {
50      "workers": [
51        "./src/main/ets/MainAbility/workers/worker.ets"
52      ]
53    }
54  }
55  ```
56
57- Automatic creation: DevEco Studio supports one-click generation of Workers. Right-click any position in the {moduleName} directory and choose **New > Worker** to generate the Worker template file and configuration information. There is no need to configure the fields in **build-profile.json5**.
58
59
60### Precautions for File URLs
61
62Before calling an API of the Worker module, you must create a Worker object. The constructor is related to the API version and requires the URL to the Worker thread file to be passed in **scriptURL**.
63
64```ts
65// Import the module.
66import { worker } from '@kit.ArkTS';
67
68// Use the following function in API version 9 and later versions:
69const worker1: worker.ThreadWorker = new worker.ThreadWorker('entry/ets/workers/worker.ets');
70// Use the following function in API version 8 and earlier versions:
71const worker2: worker.Worker = new worker.Worker('entry/ets/workers/worker.ets');
72```
73
74
75#### File URL Rules in Stage Model
76
77The requirements for **scriptURL** in the constructor are as follows:
78
79- **scriptURL** consists of {moduleName}/ets and {relativePath}.
80- {relativePath} is the relative path of the Worker thread file to the ***{moduleName}*/src/main/ets/** directory.
81
82(1) Loading a Worker thread file of an ability
83
84To load the Worker thread file of an ability, use the URL {moduleName}/ets/{relativePath}.
85
86```ts
87import { worker } from '@kit.ArkTS';
88
89// URL of the Worker thread file: "entry/src/main/ets/workers/worker.ets"
90const workerStage1: worker.ThreadWorker = new worker.ThreadWorker('entry/ets/workers/worker.ets');
91
92// URL of the Worker thread file: "testworkers/src/main/ets/ThreadFile/workers/worker.ets"
93const workerStage2: worker.ThreadWorker = new worker.ThreadWorker('testworkers/ets/ThreadFile/workers/worker.ets');
94```
95
96(2) Loading a Worker thread file from an [HSP](../quick-start/in-app-hsp.md)
97
98To load the Worker thread file from an HSP, use the URL {moduleName}/ets/{relativePath}.
99
100```ts
101import { worker } from '@kit.ArkTS';
102
103// URL of the Worker thread file: "hsp/src/main/ets/workers/worker.ets"
104const workerStage3: worker.ThreadWorker = new worker.ThreadWorker('hsp/ets/workers/worker.ets');
105```
106
107(3) Loading a Worker thread file from an [HAR](../quick-start/har-package.md)
108
109There are two scenarios for loading a Worker thread file from an HAR:
110
111- @ path loading: All types of modules load the Worker thread file from the local HAR. The URL is @{moduleName}/ets/{relativePath}.
112
113- Relative path loading: The local HAR loads the Worker thread file within the same package. The URL is the relative path of the file where the Worker object is created to the Worker thread file.
114
115>**NOTE**
116>
117>When **useNormalizedOHMUrl** is enabled (the **useNormalizedOHMUrl** field of the **strictMode** property in the application-level **build-profile.json5** file at the same level as the entry in the project directory is set to **true**) or when the HAR is used as a third-party package, the Worker thread file contained the HAR can be loaded using a relative path.
118
119```ts
120import { worker } from '@kit.ArkTS';
121
122// @ path loading:
123// URL of the Worker thread file: "har/src/main/ets/workers/worker.ets"
124const workerStage4: worker.ThreadWorker = new worker.ThreadWorker('@har/ets/workers/worker.ets');
125
126// Relative path loading:
127// URL of the Worker thread file: "har/src/main/ets/workers/worker.ets"
128// URL of the file where the Worker object is created: "har/src/main/ets/components/mainpage/MainPage.ets"
129const workerStage5: worker.ThreadWorker = new worker.ThreadWorker('../../workers/worker.ets');
130```
131
132
133#### File URL Rules in FA Model
134
135**scriptURL** in the constructor is the relative path from the Worker thread file to "{moduleName}/src/main/ets/MainAbility".
136
137```ts
138import { worker } from '@kit.ArkTS';
139
140// The following three scenarios are involved.
141
142// Scenario 1: URL of the Worker thread file: "{moduleName}/src/main/ets/MainAbility/workers/worker.ets"
143const workerFA1: worker.ThreadWorker = new worker.ThreadWorker("workers/worker.ets", {name:"first worker in FA model"});
144
145// Scenario 2: URL of the Worker thread file: "{moduleName}/src/main/ets/workers/worker.ets"
146const workerFA2: worker.ThreadWorker = new worker.ThreadWorker("../workers/worker.ets");
147
148// Scenario 3: URL of the Worker thread file: "{moduleName}/src/main/ets/MainAbility/ThreadFile/workers/worker.ets"
149const workerFA3: worker.ThreadWorker = new worker.ThreadWorker("ThreadFile/workers/worker.ets");
150```
151
152
153### Precautions for Lifecycle Management
154
155- Creating and destroying Worker consume system resources. Therefore, you are advised to manage created Workers efficiently and reuse them when possible. Idle Workers continue to run. When a Worker is no longer needed, call [terminate()](../reference/apis-arkts/js-apis-worker.md#terminate9) or [close()](../reference/apis-arkts/js-apis-worker.md#close9) to destroy it actively. If a Worker is in a non-running state such as destroyed or being destroyed, calling its functional interfaces will throw corresponding errors.
156
157
158- The number of Workers is determined by the memory management policy, with a set memory threshold being the smaller of 1.5 GB and 60% of the device's physical memory. Under memory constraints, a maximum of 64 Workers can run simultaneously. If an attempt is made to create more Workers than this limit, the system displays the error message "Worker initialization failure, the number of Workers exceeds the maximum." The actual number of running Workers will be dynamically adjusted based on current memory usage. Once the cumulative memory usage of all Workers and the main thread exceeds the set threshold, Out of Memory (OOM) error occurs, and applications may crash.
159
160
161## Basic Usage Example of Worker
162
1631. In DevEco Studio, right-click any position in the {moduleName} directory and choose **New > Worker** to automatically generate the Worker template file and configuration information. This section uses the creation of "worker" as an example.
164
165   You can also manually create Worker thread files. For specific methods and related considerations, see [Precautions for Creating a Worker](#precautions-for-creating-a-worker).
166
1672. Import the Worker module.
168
169    ```ts
170    // Index.ets
171    import { ErrorEvent, MessageEvents, worker } from '@kit.ArkTS'
172    ```
173
1743. In the host thread, call [constructor()](../reference/apis-arkts/js-apis-worker.md#constructor9) of **ThreadWorker** to create a Worker object, and register callback functions. The calling thread is the host thread.
175
176      ```ts
177      // Index.ets
178      @Entry
179      @Component
180      struct Index {
181        @State message: string = 'Hello World';
182
183        build() {
184          RelativeContainer() {
185            Text(this.message)
186              .id('HelloWorld')
187              .fontSize(50)
188              .fontWeight(FontWeight.Bold)
189              .alignRules({
190                center: { anchor: '__container__', align: VerticalAlign.Center },
191                middle: { anchor: '__container__', align: HorizontalAlign.Center }
192              })
193              .onClick(() => {
194                // Create a Worker object.
195                let workerInstance = new worker.ThreadWorker('entry/ets/workers/worker.ets');
196
197                // Register the onmessage callback. When the host thread receives a message from the Worker thread through the workerPort.postMessage interface, this callback is invoked and executed in the host thread.
198                workerInstance.onmessage = (e: MessageEvents) => {
199                  let data: string = e.data;
200                  console.info("workerInstance onmessage is: ", data);
201                }
202
203                // Register the onerror callback to capture exceptions generated during the execution of the Worker thread. This callback is executed in the host thread.
204                workerInstance.onerror = (err: ErrorEvent) => {
205                  console.info("workerInstance onerror message is: " + err.message);
206                }
207
208                // Register the onmessageerror callback. When the Worker object receives a message that cannot be serialized, this callback is invoked and executed in the host thread.
209                workerInstance.onmessageerror = () => {
210                  console.info('workerInstance onmessageerror');
211                }
212
213                // Register the onexit callback. When the Worker object is destroyed, this callback is invoked and executed in the host thread.
214                workerInstance.onexit = (e: number) => {
215                  // When the Worker object exits normally, the code is 0. When the Worker object exits abnormally, the code is 1.
216                  console.info("workerInstance onexit code is: ", e);
217                }
218
219                // Send a message to the Worker thread.
220                workerInstance.postMessage('1');
221              })
222          }
223          .height('100%')
224          .width('100%')
225        }
226      }
227      ```
228
2294. Register the callback functions in the Worker thread file.
230
231      ```ts
232      // worker.ets
233      import { ErrorEvent, MessageEvents, ThreadWorkerGlobalScope, worker } from '@kit.ArkTS';
234
235      const workerPort: ThreadWorkerGlobalScope = worker.workerPort;
236
237      // Register the onmessage callback. When the Worker thread receives a message from the host thread through the postMessage interface, this callback is invoked and executed in the Worker thread.
238      workerPort.onmessage = (e: MessageEvents) => {
239        let data: string = e.data;
240        console.info('workerPort onmessage is: ', data);
241
242        // Send a message to the main thread.
243        workerPort.postMessage('2');
244      }
245
246      // Register the onmessageerror callback. When the Worker object receives a message that cannot be serialized, this callback is invoked and executed in the Worker thread.
247      workerPort.onmessageerror = () => {
248        console.info('workerPort onmessageerror');
249      }
250
251      // Register the onerror callback. When an exception occurs during the execution of the Worker thread, this callback is invoked and executed in the Worker thread.
252      workerPort.onerror = (err: ErrorEvent) => {
253        console.info('workerPort onerror err is: ', err.message);
254      }
255      ```
256
257
258## Loading Worker Across HARs
259
2601. Create an HAR. For details, see [HAR](../quick-start/har-package.md).
261
2622. Create the Worker thread file in the HAR.
263
264   ```ts
265   // worker.ets
266   workerPort.onmessage = (e: MessageEvents) => {
267     console.info("worker thread receive message: ", e.data);
268     workerPort.postMessage('worker thread post message to main thread');
269   }
270   ```
271
2723. Configure the dependency of the HAR in the **oh-package.json5** file of the entry module.
273
274   ```ts
275   // Configure the dependency of the HAR in the entry module.
276   {
277     "name": "entry",
278     "version": "1.0.0",
279     "description": "Please describe the basic information.",
280     "main": "",
281     "author": "",
282     "license": "",
283     "dependencies": {
284       "har": "file:../har"
285     }
286   }
287   ```
288
2894. Load the Worker thread file from the HAR in the entry module.
290
291   ```ts
292   // Index.ets
293   import { worker } from '@kit.ArkTS';
294
295   @Entry
296   @Component
297   struct Index {
298     @State message: string = 'Hello World';
299
300     build() {
301       RelativeContainer() {
302         Text(this.message)
303           .id('HelloWorld')
304           .fontSize(50)
305           .fontWeight(FontWeight.Bold)
306           .alignRules({
307             center: { anchor: '__container__', align: VerticalAlign.Center },
308             middle: { anchor: '__container__', align: HorizontalAlign.Center }
309           })
310           .onClick(() => {
311             // Use @ path loading mode and load the Worker thread file from the HAR.
312             let workerInstance = new worker.ThreadWorker('@har/ets/workers/worker.ets');
313             workerInstance.onmessage = () => {
314               console.info('main thread onmessage');
315             };
316             workerInstance.postMessage('hello world');
317           })
318       }
319       .height('100%')
320       .width('100%')
321     }
322   }
323   ```
324
325
326## Multi-Level Worker Lifecycle Management
327Multi-level Workers can be created (a hierarchical thread relationship is formed by the mechanism of creating child Workers through parent Workers), and the lifecycle of Worker threads should be manually managed. Therefore, it is important to properly manage the lifecycle of multi-level Workers. If a parent Worker is destroyed without terminating its child Workers, unpredictable results may occur. It is recommended that you ensure the lifecycle of child Workers always remains within the lifecycle of the parent Worker and that all child Workers are terminated before destroying the parent Worker.
328
329
330### Recommended Usage Example
331
332```ts
333// Create a Worker thread (parent Worker) in the main thread, and create a Worker thread (child Worker) in the parent Worker.
334// main thread
335import { worker, MessageEvents, ErrorEvent } from '@kit.ArkTS';
336
337// Create a parent Worker object in the main thread.
338const parentworker = new worker.ThreadWorker("entry/ets/workers/parentworker.ets");
339
340parentworker.onmessage = (e: MessageEvents) => {
341  console.info("The main thread receives a message from the parent Worker" + e.data);
342}
343
344parentworker.onexit = () => {
345  console.info("The parent Worker exits");
346}
347
348parentworker.onerror = (err: ErrorEvent) => {
349  console.info("The main thread receives an error from the parent Worker" + err);
350}
351
352parentworker.postMessage("The main thread sends a message to the parent Worker - recommended example");
353```
354
355```ts
356// parentworker.ets
357import { ErrorEvent, MessageEvents, ThreadWorkerGlobalScope, worker } from '@kit.ArkTS';
358
359// Create an object in the parent Worker for communicating with the main thread.
360const workerPort: ThreadWorkerGlobalScope = worker.workerPort;
361
362workerPort.onmessage = (e : MessageEvents) => {
363  if (e.data == "The main thread sends a message to the parent Worker - recommended example") {
364    let childworker = new worker.ThreadWorker("entry/ets/workers/childworker.ets");
365
366    childworker.onmessage = (e: MessageEvents) => {
367      console.info("The parent Worker receives a message from the child Worker" + e.data);
368      if (e.data == "The child Worker sends information to the parent Worker") {
369        workerPort.postMessage("The parent Worker sends a message to the main thread");
370      }
371    }
372
373    childworker.onexit = () => {
374      console.info("The child Worker exits");
375      // Destroy the parent Worker after the child Worker exits.
376      workerPort.close();
377    }
378
379    childworker.onerror = (err: ErrorEvent) => {
380      console.info("An error occurred on the child Worker" + err);
381    }
382
383    childworker.postMessage("The parent Worker sends a message to the child Worker - recommended example");
384  }
385}
386```
387
388```ts
389// childworker.ets
390import { ErrorEvent, MessageEvents, ThreadWorkerGlobalScope, worker } from '@kit.ArkTS';
391
392// Create an object in the child Worker for communicating with the parent Worker.
393const workerPort: ThreadWorkerGlobalScope = worker.workerPort;
394
395workerPort.onmessage = (e: MessageEvents) => {
396  if (e.data == "The parent Worker sends a message to the child Worker - recommended example") {
397    // Service logic of the child Worker...
398    console.info("The service execution is complete, and the child Worker is destroyed");
399    workerPort.close();
400  }
401}
402```
403
404
405### Not Recommended Example
406
407It is not recommended that a child Worker send messages to the parent Worker after the parent Worker is destroyed.
408
409```ts
410// main thread
411import { worker, MessageEvents, ErrorEvent } from '@kit.ArkTS';
412
413const parentworker = new worker.ThreadWorker("entry/ets/workers/parentworker.ets");
414
415parentworker.onmessage = (e: MessageEvents) => {
416  console.info("The main thread receives a message from the parent Worker" + e.data);
417}
418
419parentworker.onexit = () => {
420  console.info("The parent Worker exits");
421}
422
423parentworker.onerror = (err: ErrorEvent) => {
424  console.info("The main thread receives an error from the parent Worker" + err);
425}
426
427parentworker.postMessage("The main thread sends a message to the parent Worker");
428```
429
430```ts
431// parentworker.ets
432import { ErrorEvent, MessageEvents, ThreadWorkerGlobalScope, worker } from '@kit.ArkTS';
433
434const workerPort: ThreadWorkerGlobalScope = worker.workerPort;
435
436workerPort.onmessage = (e : MessageEvents) => {
437  console.info("The parent Worker receives a message from the main thread" + e.data);
438
439  let childworker = new worker.ThreadWorker("entry/ets/workers/childworker.ets")
440
441  childworker.onmessage = (e: MessageEvents) => {
442    console.info("The parent Worker receives a message from the child Worker" + e.data);
443  }
444
445  childworker.onexit = () => {
446    console.info("The child Worker exits");
447    workerPort.postMessage("The parent Worker sends a message to the main thread");
448  }
449
450  childworker.onerror = (err: ErrorEvent) => {
451    console.info("An error occurred on the child Worker" + err);
452  }
453
454  childworker.postMessage("The parent Worker sends a message to the child Worker");
455
456  // Destroy the parent Worker after the child Worker is created.
457  workerPort.close();
458}
459```
460
461```ts
462// childworker.ets
463import { ErrorEvent, MessageEvents, ThreadWorkerGlobalScope, worker } from '@kit.ArkTS';
464
465const workerPort: ThreadWorkerGlobalScope = worker.workerPort;
466
467workerPort.onmessage = (e: MessageEvents) => {
468  console.info("The child Worker receives a message" + e.data);
469
470  // After the parent Worker is destroyed, the child Worker sends a message to the parent Worker. The behavior is unpredictable.
471  workerPort.postMessage("The child Worker sends a message to the parent Worker");
472  setTimeout(() => {
473    workerPort.postMessage("The child Worker sends a message to the parent Worker");
474  }, 1000);
475}
476```
477
478You are not advised to create a child Worker in the parent Worker before and after a synchronous call that clearly triggers the destruction of the parent Worker. Furthermore, avoid creating a child Worker in the parent Worker if there is any uncertainty about whether the parent Worker is being destroyed. Ensure that the parent Worker remains active before the child Worker is successfully created.
479
480```ts
481// main thread
482import { worker, MessageEvents, ErrorEvent } from '@kit.ArkTS';
483
484const parentworker = new worker.ThreadWorker("entry/ets/workers/parentworker.ets");
485
486parentworker.onmessage = (e: MessageEvents) => {
487  console.info("The main thread receives a message from the parent Worker" + e.data);
488}
489
490parentworker.onexit = () => {
491  console.info("The parent Worker exits");
492}
493
494parentworker.onerror = (err: ErrorEvent) => {
495  console.info("The main thread receives an error from the parent Worker" + err);
496}
497
498parentworker.postMessage("The main thread sends a message to the parent Worker");
499```
500
501```ts
502// parentworker.ets
503import { ErrorEvent, MessageEvents, ThreadWorkerGlobalScope, worker } from '@kit.ArkTS';
504
505const workerPort: ThreadWorkerGlobalScope = worker.workerPort;
506
507workerPort.onmessage = (e : MessageEvents) => {
508  console.info("The parent Worker receives a message from the main thread" + e.data);
509
510  // Create a child Worker after the parent Worker is destroyed. The behavior is unpredictable.
511  workerPort.close();
512  let childworker = new worker.ThreadWorker("entry/ets/workers/childworker.ets");
513
514  // Destroy the parent Worker before it is confirmed that the child Worker is successfully created. The behavior is unpredictable.
515  // let childworker = new worker.ThreadWorker("entry/ets/workers/childworker.ets");
516  // workerPort.close();
517
518  childworker.onmessage = (e: MessageEvents) => {
519    console.info("The parent Worker receives a message from the child Worker" + e.data);
520  }
521
522  childworker.onexit = () => {
523    console.info("The child Worker exits");
524    workerPort.postMessage("The parent Worker sends a message to the main thread");
525  }
526
527  childworker.onerror = (err: ErrorEvent) => {
528    console.info("An error occurred on the child Worker" + err);
529  }
530
531  childworker.postMessage("The parent Worker sends a message to the child Worker");
532}
533```
534
535```ts
536// childworker.ets
537import { ErrorEvent, MessageEvents, ThreadWorkerGlobalScope, worker } from '@kit.ArkTS';
538
539const workerPort: ThreadWorkerGlobalScope = worker.workerPort;
540
541workerPort.onmessage = (e: MessageEvents) => {
542  console.info("The child Worker receives a message" + e.data);
543}
544```
545