在前端開發(fā)過程中知纷,發(fā)現(xiàn)APP會有很多方面的性能需要注意橘洞,例如:
- APP卡頓
- 網(wǎng)絡慢
- APP加載慢
以下是一些具體的實踐經(jīng)驗婶肩。
性能優(yōu)化分為兩個方面:一個是加快靜態(tài)資源的加載,一個是提高頁面渲染的速度貌夕。
頁面渲染性能優(yōu)化
- 減少DOM層級律歼,在寫DOM的時候沒必要的層級可以不要加。
- 不需要陰影的地方啡专,不要加陰影险毁。
- 使用chrome的performance分析,分析原因们童。
靜態(tài)資源加載優(yōu)化
資源壓縮
頁面的資源包括js畔况、css、images等等慧库,這些文件盡可能壓縮
使用 tree-shaking跷跪、scope hoisting、code-splitting
- tree-shaking
移除無用代碼齐板,只加載實際使用了的代碼吵瞻。 - scope hoisting
作用域提升,允許工具檢測哪些import
可以被提升或者可以轉(zhuǎn)換成一個內(nèi)聯(lián)函數(shù)甘磨。 - Code-splitting
將代碼分為按需加載的“塊”橡羞。
緩存
HTTP緩存:如果有HTTP緩存,并且緩存沒有失效济舆,瀏覽器會直接使用緩存卿泽;反之,則向服務器請求數(shù)據(jù)滋觉。
強制緩存:
- Expires签夭,這個字段表示緩存到期時間。如果在響應消息頭中設置了這個字段椎瘟,就告知了瀏覽器在沒到這個時間之前不需要再次請求。
- Cache-Control侄旬,這個字段表示緩存的最大有效時間肺蔚,在這個時間內(nèi)客戶端不需要向服務器發(fā)送請求。
對比緩存:
- Last-Modified:服務器告知客戶端儡羔,資源最后一次被修改的時間宣羊。
- If-Modified-Since:再次發(fā)送請求時,請求頭中帶有該字段汰蜘,服務器會將If-Modified-Since的值與Last-Modified字段進行對比仇冯,如果相等,則表示未修改族操,響應304苛坚;反之比被,則表示修改了,響應200狀態(tài)碼泼舱,返回數(shù)據(jù)等缀。
推薦的用法:
- Etag:它存儲的是文件的特殊標識(一般都是hash生成的),服務器存儲著文件的Etag字段娇昙,可以在與每次客戶端傳送If-no-match的字段進行比較尺迂,如果相等,則表示未修改冒掌,響應304噪裕;反之,則表示已修改股毫,響應200狀態(tài)碼膳音,返回數(shù)據(jù)。
使用lazyload&preload
為了提高頁面的加載速度皇拣,我們期望的是按需加載严蓖,也就是說只加載當前的頁面,別的頁面不會一起被加載進來氧急,免得阻礙了當前頁面的加載颗胡。這就是懶加載,也被稱為延遲加載吩坝,延遲相關(guān)資源的加載毒姨。
當首頁加載完畢后,預判用戶行為钉寝,提前加載之后的頁面弧呐,也會提高用戶的體驗。這就是預加載嵌纲。
實踐中的一些例子
APP卡頓的時候俘枫,多次點擊觸發(fā)事件的處理
當APP卡頓時,如果多次點擊一個button逮走,剛好這個button會打開下一頁鸠蚪,那么就會看到打開了很多頁的動畫效果。為了防止這種情況师溅,考慮了很多做法茅信。
- debounce
加上一個Directive,監(jiān)聽click事件墓臭,在某個時間段內(nèi)蘸鲸,多次點擊,只觸發(fā)一次操作窿锉。
import { Directive, EventEmitter, HostListener, OnInit, Output } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { debounceTime } from 'rxjs/operators';
@Directive({
selector: '[appDebounceClick]'
})
export class DebounceClickDirective implements OnInit {
@Output() debounceClick = new EventEmitter();
private clicks = new Subject();
constructor() {}
ngOnInit() {
this.clicks.pipe(debounceTime(4000)).subscribe(e => this.debounceClick.emit(e));
}
@HostListener('click', ['$event'])
clickEvent(event) {
event.preventDefault();
event.stopPropagation();
this.clicks.next(event);
}
}
component的html:
<button appDebounceClick (debounceClick)="log()">Debounced Click</button>
component的ts文件
public log() {
// do some thing
}
具體做法參考:
https://coryrylan.com/blog/creating-a-custom-debounce-click-directive-in-angular
- disable button
其實就是在button觸發(fā)事件后酌摇,通過disable屬性來控制接下來的事件是否生效膝舅,這個需要注意button disabled樣式可能會發(fā)生變化,并且要在合適的時機來控制該button的disable妙痹。如果對于APP中全部button都做這個控制的話铸史,可以抽一個Button component,并加上disable控制怯伊。 - disable event
目前的APP中琳轿,主要遇上的問題是多次點擊button跳轉(zhuǎn)頁面時,會打開多個頁面耿芹,又不想改變button的樣式崭篡,所以在button觸發(fā)的頁面跳轉(zhuǎn)時,加上一個flag吧秕,判斷是否跳轉(zhuǎn)琉闪,在跳轉(zhuǎn)后的callback方法里重置該flag。
具體做法其實就是砸彬,創(chuàng)建一個service颠毙,里面有一個flag屬性和跳轉(zhuǎn)方法。跳轉(zhuǎn)方法中砂碉,在頁面跳轉(zhuǎn)前蛀蜜,先判斷一下該flag是否可以跳轉(zhuǎn),如果可以增蹭,進行跳轉(zhuǎn)事件滴某,并且在callback方法里面重置flag。因為這個是針對于某一個頁面的跳轉(zhuǎn)事件滋迈,所以這個service應該inject到每一個用到的page霎奢。
4.更好的辦法,繼續(xù)探索中饼灿。幕侠。。