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