WEB/H5性能優化總結

咱們今天來講說前端圖形渲染優化,由於我接下來的時間可能要開始研究webgl方面的東西,因此就在這裏把以前作過的H5作一個總結,現同步發佈於GERRY_BLOG,TiMiGerry-知乎,轉載請保留連接。

靜態資源-圖片

一 、圖片格式
JPEG: 首先JPEG compress的整個流程是將圖片的顏色rgba()進行一個轉換,而後進行重採樣區分高頻和低頻的顏色變換,從而進行一個DTA的過程,而後對高頻的顏色變換採樣結果進行一個壓縮,接着量化和encoding,最後獲得一個JPEG的壓縮版。這個壓縮版的圖片和原始數據的圖片是有差別的,雖然壓縮的過程當中丟失了一些數據,可是這些差別對於人眼是沒法識別的。因此在壓縮以後不影響總體的瀏覽體驗效果,同時對於頁面來講,靜態資源圖片的容量也能夠減小不少,從而提升網頁的加載速度。javascript

PNG: PNG圖片的是支持透明的一種圖片格式,其實質就是一個顏色的索引數據集合。它有着PNG8,PNG24,PNG32三種格式,即8位,24位,32位索引。PNG的文件格式內部有一個調色板,以PNG8 爲例:PNG爲256色+透明功能的格式,他的調色板中有 256 種顏色,即一個像素的顏色他須要8bit的數據長度去索引,也就是說PNG8圖片的顏色只有在這256種顏色中出現,因此PNG8的顏色就沒有那麼的豐富,有弊也用利,它的文件大小也是PNG文件格式中最小的一種。
而PNG24的圖片是須要2^24色,即一個像素的顏色他須要24bit去索引,因此png24去索引一種顏色須要的數據長度是png8的3倍,同時不支持透明,png32的圖片就是在png24的基礎上增長了透明的功能,PNG的圖片的選取取決於圖片的色彩。如果圖片色彩不是很豐富且比較單一的狀況下,能夠考慮使用PNG8的圖片,若是是圖片色彩很豐富則能夠選取PNG24或PNG32位的圖片以減小圖片資源的大小。PNG圖片中每種格式圖片都有一些微小的差別,實際開發中須要平衡文件大小,圖片格式,圖片質量和圖片大小在當前項目中的重要性,,才決定使用何種圖片的格式css

JPEG: 圖片的壓縮率比較高,適用於做爲背景圖片,頭圖的狀況適用於大面積背景的狀況下使用。
PNG: 格式支持透明,這種格式的圖片兼容性很好,用於一些須要進行透明的背景或者彈出層,或者說在一下狀況下須要追求體驗質量而使用PNG圖片來進行總體頁面的開發。
SVG:另一種是SVG矢量圖,這種格式最大的好處就是放大縮小不會失真和細膩度極高同時文件相對較小和是代碼內嵌的圖片格式,能有條件的話儘量使用這樣的圖片,固然這個也只能用於一些簡單的部件例如說圖標,按鈕等等一寫簡單的業務場景。html

2、圖片處理
CSS sprite:目前來說spite仍是比較經常使用的圖片整理方法,他的好處是將大大小小的圖片合併爲一張大圖,再使用圖片定位來顯示對應的圖片,這樣能夠減小頁面的請求,提升頁面加載速度。但也有個缺點就是既然是合成一張大圖,那麼不少小圖片就依賴這一張圖片,若是這個圖片沒有加載出來那麼整個頁面基本上就缺失了,但以如今的網絡來講,基本上也能夠忽略這個問題了,如今基本上是4G網絡或者wifi不存在速度慢的狀況。
Image-inline:使用BASE64格式嵌入到頁面中也是一個很好的辦法,減小htttp請求,可是實際的開發中通常也比較少這樣作,由於將圖片嵌入到HTML中其實到了後面也很差去維護,以個人開發經驗來講,通常是出現了沒辦法的狀況下才使用BASE64的圖片格式。
例如在開發項目中,圖片資源通常都會放在不一樣域的地址中,使用CANVAS生成圖片的狀況下,canvas.toDataUrl(…)會污染圖片的原來的地址,從而致使出現了跨域的問題,後端也不可由於這張圖片單獨生成的時候,這個時候用BASE64就是最簡單粗暴的解決方法。把圖片嵌入html就解決了跨域的狀況。
壓縮:將圖片放在一些工具上批量進行壓縮。前端

HTML 頁面加載渲染

1、網頁渲染的過程java

圖片描述

網頁在加載的過程當中,首先拿到的是一個HTML文本也能夠說拿到的就是一串字符串,瀏覽器parse解析器要將這個字符串進行一系列的詞法分析,將每一個標籤生成對應的一個token或者說是每一個標籤對應的對象,而後從上到下解析這些token,接着就會一步步從上到下生成對應的DOM節點。
固然在詞法分析的過程當中,就能夠解析出link script標籤,對應的web資源就會被請求加載。JavsScript會被瀏覽器內核的V8引擎進行執行,而css就與html相似,他會被解析成CSSOM,而後HTML,CSSM,SCRIPT,解析完畢以後結合,生成Rander Tree 拿到的這些基本信息以後,接着進入layout也就是佈局,最後進行渲染Paint。web

2、 HTML的加載特色
順序加載、併發加載:
順序加載指的是前面提到過的詞法分析,即瀏覽器在解析HTML頁面的時候是從上往下的,依次執行。
併發加載指的是像同一個域下的靜態資源是會同時的發起請求,就是併發請求,固然有併發請求那服務器也有併發請求的上限,例如谷歌瀏覽器一次請求統一域下的資源併發數是6。 在遇到須要大量請求圖片的時候,咱們則須要使用懶加載或者預加載來進行操做。面試

圖片描述

CSS阻塞、JS阻塞
css儘可能寫在head中,由於css加載會阻塞頁面的加載,這是有好處的,這避免了頁面加載時會出現css沒加載完而致使的出現頁面一閃的狀況,同時,css的加載是會阻塞JS的執行,但不阻塞引入JS的加載。
js儘可能寫在HTML文本的底部,由於js的引入會阻塞頁面的渲染,也依賴於DOM節點。因此,應該先讓HTML,CSS先行加載,最後加載JS,JS的加載,固然再不影響初屏的狀況下,也可使用異步加載defer,async,來加載當前不是立刻就須要的JS文件,defer的加載時基於DOM加載完畢以後,依次加載執行,而async是否是依次加載,是誰先加載完就執行誰,用這個方法須要注意JS是否依賴,JS的執行順序也是依次執行有着相互的依賴關係,阻塞後續的JS邏輯的執行,因此得排好前後。
除了defer和acync還有就是直接使用動態加載js,通常狀況下,這樣的方法會在組件的狀況下使用,封裝一個組件而後使用js動態加載JS和CSS。數據庫

Lazyload & Preload

Lazyload用於須要加載大量圖片但能夠根據用戶的操做來決定加載數量,目的是減小對服務器的請求和減小網絡流量的浪費,同時也提升了用戶的體驗度。例如一些電商的頁面展現商品,在瀏覽器滾動到的地方加載相應的數據,而不是一口氣把全部的數據所有列出來。在H5頁面中下拉刷新,上拉加載也是很常見的作法,固然這裏因爲IOS自己的瀏覽器特性也須要作一些相應的處理。 canvas

Preload用於一些須要注重用戶體驗和流暢的運行頁面交互的狀況,在頁面加載的同時先把全部的數據所有加載好以後,再打開頁面。最多見的作法就是使用加載進度條,先把全部的靜態資源先用一個數組存放好,而後依次加載計算百分比,到達100%以後在走下一步操做。後端

重繪與迴流

咱們先說一個幀的概念,目前,大部分的設備屏幕的的刷新頻率是60次/秒,也就是1000/60=1.6ms爲一幀畫面。 瀏覽器要作任何的渲染那麼他的這個渲染時間必須小於1.6ms或者儘可能接近1.6ms,不然,就會出現卡頓的現象,影響用戶體驗。 假設如今瀏覽器渲染一個動畫的時間恰好爲一幀,那麼,這一幀的畫面這會首先會從新計算style(css/dom等)接着迴流,更新tree,再進行重繪(painting),最後再進行圖層合併(Composite)。以下圖所示

圖片描述

1、重繪與迴流:
前端性能優化最關鍵的就是減小頁面的重繪與迴流。
迴流(reflow)即當前頁面的佈局和幾何屬性發生改變時,那麼就會觸發迴流的機制。
重繪( repaint)即render tree 的自己一些屬性更新了,但不影響總體的佈局,只是改變了背景,顏色等等這就叫重繪。
2、優化:
減小重繪製與迴流
避免使用會觸發迴流的一些屬性,有些屬性會觸發迴流的機制,例如:top,height等與佈局相關的屬性,舉個栗子:@keyframes animation中 位移的方法用translateX替代top,如下圖爲例:很明顯就是少了一步layout,這是由於把會觸發迴流的top屬性用translate替代,這樣就使渲染的過程減小了layout這一步,使渲染的時間減小從而提升性能。

圖片描述

圖片描述

很明顯就是少了一步layout,這是由於把會觸發迴流的top屬性用translate替代,這樣就使渲染的過程減小了layout這一步,使渲染的時間減小從而提升性能。

獨立頻繁渲染圖層,把須要進行頻繁迴流重繪的那個區塊,拿出來做爲一個單獨的圖層,使瀏覽器的迴流重繪範圍減少,從而減小cpu的資源消耗。由於,瀏覽器渲染的過程是這樣的:
現將DOM分割成多個圖層;
而後將每一個層柵格化,並將節點繪製到圖中;
而後圖層做爲紋理上傳到GPU;
最後進行圖層的重組,咱們只要對那個須要操做的圖層獨立進行重繪與迴流就不會影響到其餘的圖層。
依照上面的渲染流程,這裏就要講到一個GPU加速的概念,既然咱們建立了一個新的合成層其實也就是開啓了GPU的加速,建立新的圖層方法有如下幾種:
3D或透視轉換
使用加速視頻解碼的video元素;
擁有3D(WelGL)上下文或加速器的2D上下文canvas元素;
對本身的opactiy作css運畫或使用webkit轉換的元素;
擁有加速css過濾的元素;
元素A擁有一個z-index比本身小的元素B,且元素B是一個合成層(換句話說就是該元素在複合層上面渲染),則元素A會提高爲合成層 ;

以第2點爲例:打開英雄聯盟的比賽直播視頻:

圖片描述

咱們能夠看到,這裏video爲何會成爲一個圖層,這裏就有一個解釋。

這裏提一下第7點,由於在實際的開發項目中,尤爲是移動端作一些動畫效果的時候會常遇到的問題。

圖片描述

依照上圖的狀況,元素B應該在單獨的合成層上,而且屏幕的最終圖像應該在 GPU 上組成。可是A元素在B元素的頂部,咱們沒有指定A元素和B元素的層級。那麼瀏覽器這個時候它將強制爲元素A建立一個新的合成圖層, 這樣,A和B都被變成了單獨的合成層。所以,使用 GPU 加速提高動畫性能時,最好給當前動畫元素增長一個高一點的 z-index 屬性,人爲干擾複合層的排序,能夠有效減小 Chrome 建立沒必要要的複合層,提高渲染性能。
新建圖層的時候要注意:GPU 不只須要發送渲染層圖像到GPU ,並且還需存儲它們,以便稍後在動畫中重用。不能隨意的建立圖層,必定要結合當前項目的狀況去分析。由於建立一個新的層是有代價的,每建立一個新的渲染層,就意味着新的內存分配和更復雜的層管理。對於使用移動設備的用戶來講是一個很大的負擔。

瀏覽器存儲

1、存儲介質
Cookie:cookie通常用來存放帳戶驗證的的信息或者一些比較敏感的用戶數據,又或者是在移動端中一些項目的合做頁面須要獲取登陸態的信息時候,就能夠用一箇中轉頁的cookie來存放相應的數據,以便獲取。總的來講就是,用於C-S之間交互和自己數據存儲。由於,他的傳遞方式是先從服務器生成,而後瀏覽器在收到服務器的返回數據中header中的set-cookie把數據寫到本地,接着每次http請求(同域名下)都會夾帶cookie信息,從而讓服務器進行請求的用戶驗證

這是一個很是高效的交互機制,可是這也帶來了一些問題既然每次都會帶上cookie那麼說明若是請求數量多就會帶來流量上的消耗,會形成加載的速度慢和資源浪費,一些資源能夠用cdn解決把主站和資源站的域名分開,固然這也是創建在量大的網頁的狀況下,若是一個網頁的PV還不到10萬以上那其實以今天的網絡來講這點也能夠忽略不計。說到這裏,這讓我想起了之前去一些小公司面試的時候,當我問到他們公司web性能優化一塊的時候,那些技術負責人基本上就是一句話,「流量還沒到10萬以上的話,能看到界面正常體驗就行,怎麼方便怎麼來。「你們就哈哈的一笑。不過做爲開發者仍是要從技術的角度出發,不管項目大小,儘量作到最好。

localStrage & sessionStrage:相對於cookie這個兩個是H5新出的專門用於存儲數據的屬性,容量能夠達到5M,惟一的區別就是一個是關閉後數據還在,另外一個是瀏覽器關閉後數據清空。能夠做爲一些臨時數據的存放,例如表單或者購物車數據等。
IndexDB:這個瀏覽器的API,是一個瀏覽器數據庫,在須要存儲大量的結構化數據的時候才須要使用,目前使用這個API的仍是不多的,由於在客戶端還不要存儲特別量大的數據,數據基本是交給後臺的,前端基本上須要存儲的數據基本上就是臨時數據和驗證數據。indexDB另外一個是建立相應的離線應用。
Server Worker:這個是用於須要獲取體積大和計算量很大的js文件的時候須要用到,在3D渲染的狀況下,js的文件體積很大,計算量也很大,而js又是單線程的執行。這就有可能出現卡頓的狀況,上一個js沒處理完,下一個js就得等,SW就是獨立於當前WEB,在後臺能夠對不一樣的JS進行處理,主頁面進行監聽最後再進行彙總。下面是SW的生命週期:

圖片描述

PWA:progressive web app指的是一種新型的app模型,經過一系列的web新特性配合UI設計達到最好的用戶體驗。這也是將來WEB APP的趨勢。說白一點,就是會盡可能的貼近原生APP的體驗度,例如他的三個主要方向,第一在沒有網絡的狀況下也能夠打開APP進行使用。其二是提升相應速度,達到最好的體驗效果,另一個是生成桌面可點擊應有,就是和普通的APP同樣,經過點擊APP進入同樣有全屏和推送的功能。

瀏覽器緩存

一個好的緩存策略能夠減小http請求和網頁的延遲,減小沒必要要的數據加載,下降網絡負荷,從而提升頁面的反應速度,能讓用戶有更好的瀏覽體驗。可是,緩存只能提升第二次打開頁面的反應速度,第一次打開頁面仍是得由當前網絡環境和設備來決定。瀏覽器的緩存是將文件保存在客戶端,當每次會話時,瀏覽器都會去檢查緩存的副本是否是還在有效期以內。若是是,則瀏覽器不會再向服務端請求文件,而是直接在內存中獲取而且使用。若是文件已通過期,那麼瀏覽器纔會向服務端發起請求。這樣就能減小沒必要要的請求,加快頁面的相應。

web緩存的信息會保存在httpheader中,經過httpheader中的一些屬性去配置一些緩存策略,經過這裏策略來決定資源是否須要再次向服務端發起請求加載。能夠存在於responseheader中也能夠存在於requestheader中,目的就是讓客戶端和服務端知道相互的一個緩存狀況。

Cache-control是控制緩存策略的httpheader,這裏面有:max-age,s-maxage, private,public,no-cache,no-store經過這些屬性來進行一個緩存的配置,造成一個緩存的策略。
max-age:max-ago指的是最大的有效時間,即資源從當前請求的時間開始在這個時間範圍以內,不須要向服務器發起資源請求,瀏覽器直接獲取內存的文件使用便可,咱們打開王者榮耀的官網:

圖片描述

圖片描述

看到這裏logo,Cache-control的max-age是86400秒,換算一下86400/3600=24,也就是這個logo在一天以內,訪問這個網頁都不會向服務端發起資源請求,即便服務端的這張logo發生了變化,由圖片中可看到from memory cache,即從內存中獲取。
s-maxage :s-maxage和max-age相似,都是在指定的時間以內不會向服務端發起資源請求,可是有一點不一樣,s-maxage指向的是共享緩存(後面會進行說明),例如:cdn,而且當一個Cacha-control中同時設置了maxage和s-maxage以後,s-maxage會覆蓋掉maxage和Expires 。

private 和 public: private指的是私人緩存,即只能由用戶本身去訪問的緩存,而public指的是共享緩存是多個瀏覽器均可以去訪問的,若是沒有指定private或者public默認爲public,另外須要注意的是,s-maxage必須設置public的狀況下才能夠生效。
no-cache:指的是每一次都會想服務端發起請求驗證緩存是否過時失效,而不是向maxage那樣,在一段內就不會向服務器發起資源的請求。no-cache的用法上要注意一點,能夠將maxage設置爲0,而且屬性設置爲private:
Cache-control:private,maxage:0,no-cache

no-store指的就是禁止緩存,每次加載都須要進行資源的請求。
Expires:Expires是用來設置緩存過時時間的,他和max-age同樣,都是指定都某個時間以內,只要緩存生效就不會向服務器請求資源,可是,max-age的優先級要高於expires,且須要和last-modified一塊兒使用,由於,expires是強緩存,他在指定的時間以內是否是向服務端發起請求的,無論文件是否再服務器端發生了更新。還有一點Expires它相對來講出現得比較早,因此他在瀏覽器兼容方面是有優點的。

Last-modified&if-last-modified:last-modified&if-last-modified指的是文件最後的修改時間,是基於客戶端和服務端的緩存協商機制的 last-modified存於responseheader中 if-modifity-since存於requestheader中

圖片描述

咱們看到了responseheader中有一個last-modified中有一個時間,這是時間就是服務器上這個文件的最後修改時間,瀏覽器會把這個時間保存下來,當下次請求的的時候,requestheader中if-modified-since就會有這個時間,告訴服務器我這個文件,最後更新的是這個時間點。若是,此時服務端的文件已經發生了改變,那麼他就會從新加載,返回狀態碼200,若是,服務端的資源沒有改變,那麼瀏覽器端則會直接獲取緩存,返回304。

Etag 和 if-none-Match:由服務器端根據文件的內容生成一個hash值,來標識資源的狀態,第二次向服務端發起請求時,服務端會驗證hash是否一致,來判斷文件是否發生了變化,他能夠解決什麼問題? 僅有last-modified的狀況下會如下的缺陷:
服務器文件變化了,可是內容沒有變化;
服務器不能精確的獲取資源的最後修改時間;
資源在秒之內進行了操做,last-modified是不能識別的;

Etag就是之內容爲基準,無論有什麼操做,只要內容變化,hash值必定發生變化。 另一個是,etag的優先級要比last-modified的優先級要高。再補充一點:Last-modified&ETag是在瀏覽器進行再一次驗證的時候,纔會使用到,他要先判斷緩存過時的狀況下(max-age),再來使用這兩個東東,固然ETag的優先級是高過Last-modifity的。

緩存策略定製:
緩存策略我把它歸爲兩大類,一是靜態資源的緩存策略,而是動態資源的緩存策略,後續可能還會有新的方法,我到時再把它寫出來。先注意一點,對於緩存要先分好是共享的仍是私人的,一來避免被代理緩存,二來,養成良好注意代碼規範的習慣。

靜態資源:靜態資源指的就是css,javascript,txt,圖片等固定不會修改的文件。像css,javascript這樣的文件,咱們在打包的時候是會指定版本號的,也就是有一個名字都有一個後綴,一旦發生了變化,整個文件也就更新了。因此,對於靜態資源來講緩存的策略就比較簡單,以當前項目的狀況,作一些適當的修改便可。

動態資源: 動態資源呢,就例如股票,期貨等的價格信息,這裏資源是共享資源,瀏覽器在每次是有他們的時候瀏覽器或者代理服務器都會去檢查是否有最新的版本,那麼,咱們能夠這樣設:
Cache-control:public,no-cache,no-store
對於有些數據能夠保存一段時間的,那就max-ago=...(秒),根據須要換算一下就能夠了,例如:緩存有效一小時
Cache-control:public,max-age=86400
一個小時以後,須要嚴格的控制緩存,再次請求則可使用:
Cache-control:public,max-age=86400,no-cache or must-revalidate

其實也是根據需求來吧,設置無外乎多一條命令而已。

Vary:Accept-Encoding 這個是針對於那些啓用了gzip壓縮且被代理服務器緩存的資源,若是客戶端不支持壓縮,那麼這種狀況下可能會得不到正確的數據,這樣代理服務器可能會出現兩個版本的資源,一個是壓縮過的,另外一個是未通過壓縮的。另外一個緣由是ie瀏覽器,ie不支持任何帶有Very頭,但值不爲Accept-Encoding 和 user-Agent的資源

總結:頁面的優化方案須要根據當前項目的需求進行調整,達到實際體驗最佳的便可。

相關文章
相關標籤/搜索