W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
開發(fā)者若使用低性能的代碼實現(xiàn)功能場景可能不會影響應(yīng)用的正常運(yùn)行,但卻會對應(yīng)用的性能造成負(fù)面影響。本章節(jié)列舉出了一些可提升性能的場景供開發(fā)者參考,以避免應(yīng)用實現(xiàn)上帶來的性能劣化。
開發(fā)者在使用長列表時,如果直接采用循環(huán)渲染方式,如下所示,會一次性加載所有的列表元素,一方面會導(dǎo)致頁面啟動時間過長,影響用戶體驗,另一方面也會增加服務(wù)器的壓力和流量,加重系統(tǒng)負(fù)擔(dān)。
- @Entry
- @Component
- struct MyComponent {
- @State arr: number[] = Array.from(Array(100), (v,k) =>k); //構(gòu)造0-99的數(shù)組
- build() {
- List() {
- ForEach(this.arr, (item: number) => {
- ListItem() {
- Text(`item value: ${item}`)
- }
- }, (item: number) => item.toString())
- }
- }
- }
上述代碼會在頁面加載時將100個列表元素全部加載,這并非我們需要的,我們希望從數(shù)據(jù)源中按需迭代加載數(shù)據(jù)并創(chuàng)建相應(yīng)組件,因此需要使用數(shù)據(jù)懶加載,如下所示:
- class BasicDataSource implements IDataSource {
- private listeners: DataChangeListener[] = []
- public totalCount(): number {
- return 0
- }
- public getData(index: number): any {
- return undefined
- }
- registerDataChangeListener(listener: DataChangeListener): void {
- if (this.listeners.indexOf(listener) < 0) {
- console.info('add listener')
- this.listeners.push(listener)
- }
- }
- unregisterDataChangeListener(listener: DataChangeListener): void {
- const pos = this.listeners.indexOf(listener);
- if (pos >= 0) {
- console.info('remove listener')
- this.listeners.splice(pos, 1)
- }
- }
- notifyDataReload(): void {
- this.listeners.forEach(listener => {
- listener.onDataReloaded()
- })
- }
- notifyDataAdd(index: number): void {
- this.listeners.forEach(listener => {
- listener.onDataAdd(index)
- })
- }
- notifyDataChange(index: number): void {
- this.listeners.forEach(listener => {
- listener.onDataChange(index)
- })
- }
- notifyDataDelete(index: number): void {
- this.listeners.forEach(listener => {
- listener.onDataDelete(index)
- })
- }
- notifyDataMove(from: number, to: number): void {
- this.listeners.forEach(listener => {
- listener.onDataMove(from, to)
- })
- }
- }
- class MyDataSource extends BasicDataSource {
- private dataArray: string[] = ['item value: 0', 'item value: 1', 'item value: 2']
- public totalCount(): number {
- return this.dataArray.length
- }
- public getData(index: number): any {
- return this.dataArray[index]
- }
- public addData(index: number, data: string): void {
- this.dataArray.splice(index, 0, data)
- this.notifyDataAdd(index)
- }
- public pushData(data: string): void {
- this.dataArray.push(data)
- this.notifyDataAdd(this.dataArray.length - 1)
- }
- }
- @Entry
- @Component
- struct MyComponent {
- private data: MyDataSource = new MyDataSource()
- build() {
- List() {
- LazyForEach(this.data, (item: string) => {
- ListItem() {
- Row() {
- Text(item).fontSize(20).margin({ left: 10 })
- }
- }
- .onClick(() => {
- this.data.pushData('item value: ' + this.data.totalCount())
- })
- }, item => item)
- }
- }
- }
上述代碼在頁面加載時僅初始化加載三個列表元素,之后每點擊一次列表元素,將增加一個列表元素。
在使用Scroll容器組件嵌套List組件加載長列表時,若不指定List的寬高尺寸,則默認(rèn)全部加載。
Scroll嵌套List時:
- class BasicDataSource implements IDataSource {
- private listeners: DataChangeListener[] = []
- public totalCount(): number {
- return 0
- }
- public getData(index: number): any {
- return undefined
- }
- registerDataChangeListener(listener: DataChangeListener): void {
- if (this.listeners.indexOf(listener) < 0) {
- console.info('add listener')
- this.listeners.push(listener)
- }
- }
- unregisterDataChangeListener(listener: DataChangeListener): void {
- const pos = this.listeners.indexOf(listener);
- if (pos >= 0) {
- console.info('remove listener')
- this.listeners.splice(pos, 1)
- }
- }
- notifyDataReload(): void {
- this.listeners.forEach(listener => {
- listener.onDataReloaded()
- })
- }
- notifyDataAdd(index: number): void {
- this.listeners.forEach(listener => {
- listener.onDataAdd(index)
- })
- }
- notifyDataChange(index: number): void {
- this.listeners.forEach(listener => {
- listener.onDataChange(index)
- })
- }
- notifyDataDelete(index: number): void {
- this.listeners.forEach(listener => {
- listener.onDataDelete(index)
- })
- }
- notifyDataMove(from: number, to: number): void {
- this.listeners.forEach(listener => {
- listener.onDataMove(from, to)
- })
- }
- }
- class MyDataSource extends BasicDataSource {
- private dataArray: Array<string> = new Array(100).fill('test')
- public totalCount(): number {
- return this.dataArray.length
- }
- public getData(index: number): any {
- return this.dataArray[index]
- }
- public addData(index: number, data: string): void {
- this.dataArray.splice(index, 0, data)
- this.notifyDataAdd(index)
- }
- public pushData(data: string): void {
- this.dataArray.push(data)
- this.notifyDataAdd(this.dataArray.length - 1)
- }
- }
- @Entry
- @Component
- struct MyComponent {
- private data: MyDataSource = new MyDataSource()
- build() {
- Scroll() {
- List() {
- LazyForEach(this.data, (item: string, index: number) => {
- ListItem() {
- Row() {
- Text('item value: ' + item + (index + 1)).fontSize(20).margin(10)
- }
- }
- })
- }
- }
- }
- }
因此,此場景下建議設(shè)置List子組件的寬高。
- class BasicDataSource implements IDataSource {
- private listeners: DataChangeListener[] = []
- public totalCount(): number {
- return 0
- }
- public getData(index: number): any {
- return undefined
- }
- registerDataChangeListener(listener: DataChangeListener): void {
- if (this.listeners.indexOf(listener) < 0) {
- console.info('add listener')
- this.listeners.push(listener)
- }
- }
- unregisterDataChangeListener(listener: DataChangeListener): void {
- const pos = this.listeners.indexOf(listener);
- if (pos >= 0) {
- console.info('remove listener')
- this.listeners.splice(pos, 1)
- }
- }
- notifyDataReload(): void {
- this.listeners.forEach(listener => {
- listener.onDataReloaded()
- })
- }
- notifyDataAdd(index: number): void {
- this.listeners.forEach(listener => {
- listener.onDataAdd(index)
- })
- }
- notifyDataChange(index: number): void {
- this.listeners.forEach(listener => {
- listener.onDataChange(index)
- })
- }
- notifyDataDelete(index: number): void {
- this.listeners.forEach(listener => {
- listener.onDataDelete(index)
- })
- }
- notifyDataMove(from: number, to: number): void {
- this.listeners.forEach(listener => {
- listener.onDataMove(from, to)
- })
- }
- }
- class MyDataSource extends BasicDataSource {
- private dataArray: Array<string> = new Array(100).fill('test')
- public totalCount(): number {
- return this.dataArray.length
- }
- public getData(index: number): any {
- return this.dataArray[index]
- }
- public addData(index: number, data: string): void {
- this.dataArray.splice(index, 0, data)
- this.notifyDataAdd(index)
- }
- public pushData(data: string): void {
- this.dataArray.push(data)
- this.notifyDataAdd(this.dataArray.length - 1)
- }
- }
- @Entry
- @Component
- struct MyComponent {
- private data: MyDataSource = new MyDataSource()
- build() {
- Scroll() {
- List() {
- LazyForEach(this.data, (item: string, index: number) => {
- ListItem() {
- Text('item value: ' + item + (index + 1)).fontSize(20).margin(10)
- }.width('100%')
- })
- }.width('100%').height(500)
- }.backgroundColor(Color.Pink)
- }
- }
如下所示,開發(fā)者在使用visibility通用屬性控制組件的顯隱狀態(tài)時,仍存在組件的重新創(chuàng)建過程,造成性能上的損耗。
- @Entry
- @Component
- struct MyComponent {
- @State isVisible: Visibility = Visibility.Visible;
- build() {
- Column() {
- Button("顯隱切換")
- .onClick(() => {
- if (this.isVisible == Visibility.Visible) {
- this.isVisible = Visibility.None
- } else {
- this.isVisible = Visibility.Visible
- }
- })
- Row().visibility(this.isVisible)
- .width(300).height(300).backgroundColor(Color.Pink)
- }.width('100%')
- }
- }
要避免這一問題,可使用if條件渲染代替visibility屬性變換,如下所示:
- @Entry
- @Component
- struct MyComponent {
- @State isVisible: boolean = true;
- build() {
- Column() {
- Button("顯隱切換")
- .onClick(() => {
- this.isVisible = !this.isVisible
- })
- if (this.isVisible) {
- Row()
- .width(300).height(300).backgroundColor(Color.Pink)
- }
- }.width('100%')
- }
- }
由于Flex容器組件默認(rèn)情況下存在shrink導(dǎo)致二次布局,這會在一定程度上造成頁面渲染上的性能劣化。
- @Entry
- @Component
- struct MyComponent {
- build() {
- Flex({ direction: FlexDirection.Column }) {
- Flex().width(300).height(200).backgroundColor(Color.Pink)
- Flex().width(300).height(200).backgroundColor(Color.Yellow)
- Flex().width(300).height(200).backgroundColor(Color.Grey)
- }
- }
- }
上述代碼可將Flex替換為Column、Row,在保證實現(xiàn)的頁面布局效果相同的前提下避免Flex二次布局帶來的負(fù)面影響。
- @Entry
- @Component
- struct MyComponent {
- build() {
- Column() {
- Row().width(300).height(200).backgroundColor(Color.Pink)
- Row().width(300).height(200).backgroundColor(Color.Yellow)
- Row().width(300).height(200).backgroundColor(Color.Grey)
- }
- }
- }
應(yīng)用通過增大List/Grid控件的cachedCount參數(shù),調(diào)整UI的加載范圍。cachedCount表示屏幕外List/Grid預(yù)加載item的個數(shù)。
如果需要請求網(wǎng)絡(luò)圖片,可以在item滑動到屏幕顯示之前,提前下載好內(nèi)容,從而減少滑動白塊。
如下是使用cachedCount參數(shù)的例子:
- @Entry
- @Component
- struct MyComponent {
- private source: MyDataSource = new MyDataSource();
- build() {
- List() {
- LazyForEach(this.source, item => {
- ListItem() {
- Text("Hello" + item)
- .fontSize(50)
- .onAppear(() => {
- console.log("appear:" + item)
- })
- }
- })
- }.cachedCount(3) // 擴(kuò)大數(shù)值appear日志范圍會變大
- }
- }
- class MyDataSource implements IDataSource {
- data: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
- public totalCount(): number {
- return this.data.length
- }
- public getData(index: number): any {
- return this.data[index]
- }
- registerDataChangeListener(listener: DataChangeListener): void {
- }
- unregisterDataChangeListener(listener: DataChangeListener): void {
- }
- }
使用說明:
cachedCount的增加會增大UI的cpu、內(nèi)存開銷。使用時需要根據(jù)實際情況,綜合性能和用戶體驗進(jìn)行調(diào)整。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: