1e41f4b71Sopenharmony_ci# Speeding Up Application Response
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ciThis topic provides the following tips for improving your application's response to user input.
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ci- Prevent the main thread from being blocked by non-UI tasks.
6e41f4b71Sopenharmony_ci- Reduce the number of components to be refreshed.
7e41f4b71Sopenharmony_ci
8e41f4b71Sopenharmony_ci## Preventing Main Thread from Being Blocked by Non-UI Tasks
9e41f4b71Sopenharmony_ci
10e41f4b71Sopenharmony_ciWhen the application responds to user input, its main thread should execute only UI tasks (such as preparation of data to be displayed and update of visible components). It is recommended that non-UI, time-consuming tasks (such as long-time content loading) be executed through asynchronous tasks or allocated to other threads.
11e41f4b71Sopenharmony_ci
12e41f4b71Sopenharmony_ci### Using Asynchronous Component Loading
13e41f4b71Sopenharmony_ci
14e41f4b71Sopenharmony_ciThe **\<Image>** component has the asynchronous loading feature enabled by default. When an application loads a batch of local images to be displayed on the page, blank placeholder icons are displayed first, and then replaced by the images when these images have finished loading in other threads. In this way, image loading does not block page display. The following code is recommended only when the image loading takes a short time.
15e41f4b71Sopenharmony_ci
16e41f4b71Sopenharmony_ci```typescript
17e41f4b71Sopenharmony_ci@Entry
18e41f4b71Sopenharmony_ci@Component
19e41f4b71Sopenharmony_cistruct ImageExample1 {
20e41f4b71Sopenharmony_ci  build() {
21e41f4b71Sopenharmony_ci    Column() {
22e41f4b71Sopenharmony_ci      Row() {
23e41f4b71Sopenharmony_ci        Image('resources/base/media/sss001.jpg')
24e41f4b71Sopenharmony_ci          .border({ width: 1 }).borderStyle(BorderStyle.Dashed).aspectRatio(1).width('25%').height('12.5%')
25e41f4b71Sopenharmony_ci        Image('resources/base/media/sss002.jpg')
26e41f4b71Sopenharmony_ci          .border({ width: 1 }).borderStyle(BorderStyle.Dashed).aspectRatio(1).width('25%').height('12.5%')
27e41f4b71Sopenharmony_ci        Image('resources/base/media/sss003.jpg')
28e41f4b71Sopenharmony_ci          .border({ width: 1 }).borderStyle(BorderStyle.Dashed).aspectRatio(1).width('25%').height('12.5%')
29e41f4b71Sopenharmony_ci        Image('resources/base/media/sss004.jpg')
30e41f4b71Sopenharmony_ci          .border({ width: 1 }).borderStyle(BorderStyle.Dashed).aspectRatio(1).width('25%').height('12.5%')
31e41f4b71Sopenharmony_ci      }
32e41f4b71Sopenharmony_ci    // Several <Row> containers are omitted here. Each container contains the preceding <Image> components.
33e41f4b71Sopenharmony_ci    }
34e41f4b71Sopenharmony_ci  }
35e41f4b71Sopenharmony_ci}
36e41f4b71Sopenharmony_ci```
37e41f4b71Sopenharmony_ci
38e41f4b71Sopenharmony_ciRecommendation: If it takes a short time to load an image, the benefits of asynchronous loading will be greatly undermined. In this case, change the value of the syncLoad attribute.
39e41f4b71Sopenharmony_ci
40e41f4b71Sopenharmony_ci```typescript
41e41f4b71Sopenharmony_ci@Entry
42e41f4b71Sopenharmony_ci@Component
43e41f4b71Sopenharmony_cistruct ImageExample2 {
44e41f4b71Sopenharmony_ci  build() {
45e41f4b71Sopenharmony_ci    Column() {
46e41f4b71Sopenharmony_ci      Row() {
47e41f4b71Sopenharmony_ci        Image('resources/base/media/sss001.jpg')
48e41f4b71Sopenharmony_ci          .border({ width: 1 }).borderStyle(BorderStyle.Dashed).aspectRatio(1).width('25%').height('12.5%').syncLoad(true)
49e41f4b71Sopenharmony_ci        Image('resources/base/media/sss002.jpg')
50e41f4b71Sopenharmony_ci          .border({ width: 1 }).borderStyle(BorderStyle.Dashed).aspectRatio(1).width('25%').height('12.5%').syncLoad(true)
51e41f4b71Sopenharmony_ci        Image('resources/base/media/sss003.jpg')
52e41f4b71Sopenharmony_ci          .border({ width: 1 }).borderStyle(BorderStyle.Dashed).aspectRatio(1).width('25%').height('12.5%').syncLoad(true)
53e41f4b71Sopenharmony_ci        Image('resources/base/media/sss004.jpg')
54e41f4b71Sopenharmony_ci          .border({ width: 1 }).borderStyle(BorderStyle.Dashed).aspectRatio(1).width('25%').height('12.5%').syncLoad(true)
55e41f4b71Sopenharmony_ci      }
56e41f4b71Sopenharmony_ci    // Several <Row> containers are omitted here. Each container contains the preceding <Image> components.
57e41f4b71Sopenharmony_ci    }
58e41f4b71Sopenharmony_ci  }
59e41f4b71Sopenharmony_ci}
60e41f4b71Sopenharmony_ci```
61e41f4b71Sopenharmony_ci
62e41f4b71Sopenharmony_ci### Using TaskPool for Asynchronous Processing
63e41f4b71Sopenharmony_ci
64e41f4b71Sopenharmony_ciCompared with the worker thread, [TaskPool](../reference/apis/js-apis-taskpool.md) provides the task priority setting and automatic thread pool management mechanism. The following is an example:
65e41f4b71Sopenharmony_ci
66e41f4b71Sopenharmony_ci```typescript
67e41f4b71Sopenharmony_ciimport taskpool from '@ohos.taskpool';
68e41f4b71Sopenharmony_ci
69e41f4b71Sopenharmony_ci@Concurrent
70e41f4b71Sopenharmony_cifunction computeTask(arr: string[]): string[] {
71e41f4b71Sopenharmony_ci  // Simulate a compute-intensive task.
72e41f4b71Sopenharmony_ci  let count = 0;
73e41f4b71Sopenharmony_ci  while (count < 100000000) {
74e41f4b71Sopenharmony_ci    count++;
75e41f4b71Sopenharmony_ci  }
76e41f4b71Sopenharmony_ci  return arr.reverse();
77e41f4b71Sopenharmony_ci}
78e41f4b71Sopenharmony_ci
79e41f4b71Sopenharmony_ci@Entry
80e41f4b71Sopenharmony_ci@Component
81e41f4b71Sopenharmony_cistruct AspectRatioExample3 {
82e41f4b71Sopenharmony_ci  @State children: string[] = ['1', '2', '3', '4', '5', '6'];
83e41f4b71Sopenharmony_ci
84e41f4b71Sopenharmony_ci  aboutToAppear() {
85e41f4b71Sopenharmony_ci    this.computeTaskInTaskPool();
86e41f4b71Sopenharmony_ci  }
87e41f4b71Sopenharmony_ci
88e41f4b71Sopenharmony_ci  async computeTaskInTaskPool() {
89e41f4b71Sopenharmony_ci    const param = this.children.slice();
90e41f4b71Sopenharmony_ci    let task = new taskpool.Task(computeTask, param);
91e41f4b71Sopenharmony_ci    await taskpool.execute(task);
92e41f4b71Sopenharmony_ci  }
93e41f4b71Sopenharmony_ci
94e41f4b71Sopenharmony_ci  build() {
95e41f4b71Sopenharmony_ci    // Component layout
96e41f4b71Sopenharmony_ci  }
97e41f4b71Sopenharmony_ci}
98e41f4b71Sopenharmony_ci```
99e41f4b71Sopenharmony_ci
100e41f4b71Sopenharmony_ci### Creating Asynchronous Tasks
101e41f4b71Sopenharmony_ci
102e41f4b71Sopenharmony_ciThe following code shows how to declare a long-running non-UI task as an asynchronous task through **Promise**. This allows the main thread to first focus on providing user feedback and completing the initial render, and then execute the asynchronous task when it is idle. After the asynchronous task is complete, related components are redrawn to refresh the page.
103e41f4b71Sopenharmony_ci
104e41f4b71Sopenharmony_ci```typescript
105e41f4b71Sopenharmony_ci@Entry
106e41f4b71Sopenharmony_ci@Component
107e41f4b71Sopenharmony_cistruct AspectRatioExample4 {
108e41f4b71Sopenharmony_ci  @State private children: string[] = ['1', '2', '3', '4', '5', '6'];
109e41f4b71Sopenharmony_ci  private count: number = 0;
110e41f4b71Sopenharmony_ci
111e41f4b71Sopenharmony_ci  aboutToAppear() {
112e41f4b71Sopenharmony_ci    this.computeTaskAsync(); // Invoke the asynchronous compute function.
113e41f4b71Sopenharmony_ci  }
114e41f4b71Sopenharmony_ci
115e41f4b71Sopenharmony_ci  // Simulate a compute-intensive task.
116e41f4b71Sopenharmony_ci  computeTask() {
117e41f4b71Sopenharmony_ci    this.count = 0;
118e41f4b71Sopenharmony_ci    while (this.count < 100000000) {
119e41f4b71Sopenharmony_ci      this.count++;
120e41f4b71Sopenharmony_ci    }
121e41f4b71Sopenharmony_ci    this.children = this.children.reverse();
122e41f4b71Sopenharmony_ci  }
123e41f4b71Sopenharmony_ci
124e41f4b71Sopenharmony_ci  computeTaskAsync() {
125e41f4b71Sopenharmony_ci    setTimeout(() => {// setTimeout is used to implement asynchronous processing.
126e41f4b71Sopenharmony_ci      this.computeTask();
127e41f4b71Sopenharmony_ci    }, 1000)
128e41f4b71Sopenharmony_ci  }
129e41f4b71Sopenharmony_ci
130e41f4b71Sopenharmony_ci  build() {
131e41f4b71Sopenharmony_ci    // Component layout
132e41f4b71Sopenharmony_ci  }
133e41f4b71Sopenharmony_ci}
134e41f4b71Sopenharmony_ci```
135e41f4b71Sopenharmony_ci
136e41f4b71Sopenharmony_ci## Reducing the Number of Components to Be Refreshed
137e41f4b71Sopenharmony_ci
138e41f4b71Sopenharmony_ciWhen an application refreshes a page, the number of components to be refreshed must be reduced as much as possible. If this number is too large, the main thread will take a long time to perform measurement and layout. In addition, the **aboutToAppear()** and **aboutToDisappear()** APIs will be called multiple times during the creation and destruction of custom components, increasing the load of the main thread.
139e41f4b71Sopenharmony_ci
140e41f4b71Sopenharmony_ci### Limiting the Refresh Scope with Containers
141e41f4b71Sopenharmony_ci
142e41f4b71Sopenharmony_ciNegative example: If a component in a container is included in the **if** condition, changes in the **if** condition result will trigger the creation and destruction of the component. If the container layout is affected in this case, all components in the container are refreshed. As a result, the UI refresh of the main thread takes a long time.
143e41f4b71Sopenharmony_ci
144e41f4b71Sopenharmony_ciIn the following example, the **Text('New Page')** component is controlled by the state variable **isVisible**. When **isVisible** is set to **true**, the component is created. When **isVisible** is set to **false**, the component is destroyed. This means that, when the value of **isVisible** changes, all components in the **\<Stack>** container are refreshed.
145e41f4b71Sopenharmony_ci
146e41f4b71Sopenharmony_ci```typescript
147e41f4b71Sopenharmony_ci@Entry
148e41f4b71Sopenharmony_ci@Component
149e41f4b71Sopenharmony_cistruct StackExample5 {
150e41f4b71Sopenharmony_ci  @State isVisible : boolean = false;
151e41f4b71Sopenharmony_ci
152e41f4b71Sopenharmony_ci  build() {
153e41f4b71Sopenharmony_ci    Column() {
154e41f4b71Sopenharmony_ci      Stack({alignContent: Alignment.Top}) {
155e41f4b71Sopenharmony_ci        Text().width('100%').height('70%').backgroundColor(0xd2cab3)
156e41f4b71Sopenharmony_ci          .align(Alignment.Center).textAlign(TextAlign.Center);
157e41f4b71Sopenharmony_ci
158e41f4b71Sopenharmony_ci        // 100 identical <Text> components are omitted here.
159e41f4b71Sopenharmony_ci
160e41f4b71Sopenharmony_ci        if (this.isVisible) {
161e41f4b71Sopenharmony_ci          Text('New Page').height("100%").height("70%").backgroundColor(0xd2cab3)
162e41f4b71Sopenharmony_ci            .align(Alignment.Center).textAlign(TextAlign.Center);
163e41f4b71Sopenharmony_ci        }
164e41f4b71Sopenharmony_ci      }
165e41f4b71Sopenharmony_ci      Button("press").onClick(() => {
166e41f4b71Sopenharmony_ci        this.isVisible = !(this.isVisible);
167e41f4b71Sopenharmony_ci      })
168e41f4b71Sopenharmony_ci    }
169e41f4b71Sopenharmony_ci  }
170e41f4b71Sopenharmony_ci}
171e41f4b71Sopenharmony_ci```
172e41f4b71Sopenharmony_ci
173e41f4b71Sopenharmony_ciRecommendation: For the component controlled by the state variable, add a container to the **if** statement to reduce the refresh scope.
174e41f4b71Sopenharmony_ci
175e41f4b71Sopenharmony_ci```typescript
176e41f4b71Sopenharmony_ci@Entry
177e41f4b71Sopenharmony_ci@Component
178e41f4b71Sopenharmony_cistruct StackExample6 {
179e41f4b71Sopenharmony_ci  @State isVisible : boolean = false;
180e41f4b71Sopenharmony_ci
181e41f4b71Sopenharmony_ci  build() {
182e41f4b71Sopenharmony_ci    Column() {
183e41f4b71Sopenharmony_ci      Stack({alignContent: Alignment.Top}) {
184e41f4b71Sopenharmony_ci        Text().width('100%').height('70%').backgroundColor(0xd2cab3)
185e41f4b71Sopenharmony_ci          .align(Alignment.Center).textAlign(TextAlign.Center);
186e41f4b71Sopenharmony_ci
187e41f4b71Sopenharmony_ci        // 100 identical <Text> components are omitted here.
188e41f4b71Sopenharmony_ci
189e41f4b71Sopenharmony_ci        Stack() {
190e41f4b71Sopenharmony_ci          if (this.isVisible) {
191e41f4b71Sopenharmony_ci            Text('New Page').height("100%").height("70%").backgroundColor(0xd2cab3)
192e41f4b71Sopenharmony_ci              .align(Alignment.Center).textAlign(TextAlign.Center);
193e41f4b71Sopenharmony_ci          }
194e41f4b71Sopenharmony_ci        }.width('100%').height('70%')
195e41f4b71Sopenharmony_ci      }
196e41f4b71Sopenharmony_ci      Button("press").onClick(() => {
197e41f4b71Sopenharmony_ci        this.isVisible = !(this.isVisible);
198e41f4b71Sopenharmony_ci      })
199e41f4b71Sopenharmony_ci    }
200e41f4b71Sopenharmony_ci  }
201e41f4b71Sopenharmony_ci}
202e41f4b71Sopenharmony_ci```
203e41f4b71Sopenharmony_ci
204e41f4b71Sopenharmony_ci### Implementing On-Demand Loading of List Items
205e41f4b71Sopenharmony_ci
206e41f4b71Sopenharmony_ciNegative example: Each of the 10000 elements in **this.arr** is initialized and loaded. As a result, the execution of the main thread takes a long time.
207e41f4b71Sopenharmony_ci
208e41f4b71Sopenharmony_ci```typescript
209e41f4b71Sopenharmony_ci@Entry
210e41f4b71Sopenharmony_ci@Component
211e41f4b71Sopenharmony_cistruct MyComponent7 {
212e41f4b71Sopenharmony_ci  @State arr: number[] = Array.from(Array<number>(10000), (v,k) =>k); 
213e41f4b71Sopenharmony_ci  build() {
214e41f4b71Sopenharmony_ci    List() {
215e41f4b71Sopenharmony_ci      ForEach(this.arr, (item: number) => {
216e41f4b71Sopenharmony_ci        ListItem() {
217e41f4b71Sopenharmony_ci          Text(`item value: ${item}`)
218e41f4b71Sopenharmony_ci        }
219e41f4b71Sopenharmony_ci      }, (item: number) => item.toString())
220e41f4b71Sopenharmony_ci    }
221e41f4b71Sopenharmony_ci  }
222e41f4b71Sopenharmony_ci}
223e41f4b71Sopenharmony_ci```
224e41f4b71Sopenharmony_ci
225e41f4b71Sopenharmony_ciRecommendation: In similar cases, replace **ForEach** with **LazyForEach** so that only visible elements are loaded.
226e41f4b71Sopenharmony_ci
227e41f4b71Sopenharmony_ci```typescript
228e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource {
229e41f4b71Sopenharmony_ci  private listeners: DataChangeListener[] = []
230e41f4b71Sopenharmony_ci
231e41f4b71Sopenharmony_ci  public totalCount(): number {
232e41f4b71Sopenharmony_ci    return 0
233e41f4b71Sopenharmony_ci  }
234e41f4b71Sopenharmony_ci
235e41f4b71Sopenharmony_ci  public getData(index: number): string {
236e41f4b71Sopenharmony_ci    return ''
237e41f4b71Sopenharmony_ci  }
238e41f4b71Sopenharmony_ci
239e41f4b71Sopenharmony_ci  registerDataChangeListener(listener: DataChangeListener): void {
240e41f4b71Sopenharmony_ci    if (this.listeners.indexOf(listener) < 0) {
241e41f4b71Sopenharmony_ci      console.info('add listener')
242e41f4b71Sopenharmony_ci      this.listeners.push(listener)
243e41f4b71Sopenharmony_ci    }
244e41f4b71Sopenharmony_ci  }
245e41f4b71Sopenharmony_ci
246e41f4b71Sopenharmony_ci  unregisterDataChangeListener(listener: DataChangeListener): void {
247e41f4b71Sopenharmony_ci    const pos = this.listeners.indexOf(listener);
248e41f4b71Sopenharmony_ci    if (pos >= 0) {
249e41f4b71Sopenharmony_ci      console.info('remove listener')
250e41f4b71Sopenharmony_ci      this.listeners.splice(pos, 1)
251e41f4b71Sopenharmony_ci    }
252e41f4b71Sopenharmony_ci  }
253e41f4b71Sopenharmony_ci
254e41f4b71Sopenharmony_ci  notifyDataReload(): void {
255e41f4b71Sopenharmony_ci    this.listeners.forEach(listener => {
256e41f4b71Sopenharmony_ci      listener.onDataReloaded()
257e41f4b71Sopenharmony_ci    })
258e41f4b71Sopenharmony_ci  }
259e41f4b71Sopenharmony_ci
260e41f4b71Sopenharmony_ci  notifyDataAdd(index: number): void {
261e41f4b71Sopenharmony_ci    this.listeners.forEach(listener => {
262e41f4b71Sopenharmony_ci      listener.onDataAdd(index)
263e41f4b71Sopenharmony_ci    })
264e41f4b71Sopenharmony_ci  }
265e41f4b71Sopenharmony_ci
266e41f4b71Sopenharmony_ci  notifyDataChange(index: number): void {
267e41f4b71Sopenharmony_ci    this.listeners.forEach(listener => {
268e41f4b71Sopenharmony_ci      listener.onDataChange(index)
269e41f4b71Sopenharmony_ci    })
270e41f4b71Sopenharmony_ci  }
271e41f4b71Sopenharmony_ci
272e41f4b71Sopenharmony_ci  notifyDataDelete(index: number): void {
273e41f4b71Sopenharmony_ci    this.listeners.forEach(listener => {
274e41f4b71Sopenharmony_ci      listener.onDataDelete(index)
275e41f4b71Sopenharmony_ci    })
276e41f4b71Sopenharmony_ci  }
277e41f4b71Sopenharmony_ci
278e41f4b71Sopenharmony_ci  notifyDataMove(from: number, to: number): void {
279e41f4b71Sopenharmony_ci    this.listeners.forEach(listener => {
280e41f4b71Sopenharmony_ci      listener.onDataMove(from, to)
281e41f4b71Sopenharmony_ci    })
282e41f4b71Sopenharmony_ci  }
283e41f4b71Sopenharmony_ci}
284e41f4b71Sopenharmony_ci
285e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource {
286e41f4b71Sopenharmony_ci  private dataArray: string[] = Array.from(Array<number>(10000), (v, k) => k.toString());
287e41f4b71Sopenharmony_ci
288e41f4b71Sopenharmony_ci  public totalCount(): number {
289e41f4b71Sopenharmony_ci    return this.dataArray.length
290e41f4b71Sopenharmony_ci  }
291e41f4b71Sopenharmony_ci
292e41f4b71Sopenharmony_ci  public getData(index: number): string  {
293e41f4b71Sopenharmony_ci    return this.dataArray[index]
294e41f4b71Sopenharmony_ci  }
295e41f4b71Sopenharmony_ci
296e41f4b71Sopenharmony_ci  public addData(index: number, data: string): void {
297e41f4b71Sopenharmony_ci    this.dataArray.splice(index, 0, data)
298e41f4b71Sopenharmony_ci    this.notifyDataAdd(index)
299e41f4b71Sopenharmony_ci  }
300e41f4b71Sopenharmony_ci
301e41f4b71Sopenharmony_ci  public pushData(data: string): void {
302e41f4b71Sopenharmony_ci    this.dataArray.push(data)
303e41f4b71Sopenharmony_ci    this.notifyDataAdd(this.dataArray.length - 1)
304e41f4b71Sopenharmony_ci  }
305e41f4b71Sopenharmony_ci}
306e41f4b71Sopenharmony_ci
307e41f4b71Sopenharmony_ci@Entry
308e41f4b71Sopenharmony_ci@Component
309e41f4b71Sopenharmony_cistruct MyComponent {
310e41f4b71Sopenharmony_ci  private data: MyDataSource = new MyDataSource()
311e41f4b71Sopenharmony_ci
312e41f4b71Sopenharmony_ci  build() {
313e41f4b71Sopenharmony_ci    List() {
314e41f4b71Sopenharmony_ci      LazyForEach(this.data, (item: string) => {
315e41f4b71Sopenharmony_ci        ListItem() {
316e41f4b71Sopenharmony_ci            Text(item).fontSize(20).margin({ left: 10 })
317e41f4b71Sopenharmony_ci        }
318e41f4b71Sopenharmony_ci      }, (item:string) => item)
319e41f4b71Sopenharmony_ci    }
320e41f4b71Sopenharmony_ci  }
321e41f4b71Sopenharmony_ci}
322e41f4b71Sopenharmony_ci```
323