摘要:如下圖所示一重繪與回流前端性能優化最關鍵的就是減少頁面的重繪與回流。很明顯就是少了一步,這是因為把會觸發回流的屬性用替代,這樣就使渲染的過程減少了這一步,使渲染的時間減少從而提高性能。
我們今天來說說前端圖形渲染優化,因為我接下來的時間可能要開始研究webgl方面的東西,所以就在這里把之前做過的H5做一個總結,現同步發布于GERRY_BLOG,TiMiGerry-知乎,轉載請保留鏈接。靜態資源-圖片
一 、圖片格式
JPEG: 首先JPEG compress的整個流程是將圖片的顏色rgba()進行一個轉換,然后進行重采樣區分高頻和低頻的顏色變換,從而進行一個DTA的過程,然后對高頻的顏色變換采樣結果進行一個壓縮,接著量化和encoding,最后得到一個JPEG的壓縮版。這個壓縮版的圖片和原始數據的圖片是有差異的,雖然壓縮的過程中丟失了一些數據,但是這些差異對于人眼是無法識別的。所以在壓縮之后不影響整體的瀏覽體驗效果,同時對于頁面來說,靜態資源圖片的容量也可以減少很多,從而提高網頁的加載速度。
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圖片中每種格式圖片都有一些微小的差異,實際開發中需要平衡文件大小,圖片格式,圖片質量和圖片大小在當前項目中的重要性,,才決定使用何種圖片的格式
JPEG: 圖片的壓縮率比較高,適用于作為背景圖片,頭圖的情況適用于大面積背景的情況下使用。
PNG: 格式支持透明,這種格式的圖片兼容性很好,用于一些需要進行透明的背景或者彈出層,或者說在一下情況下需要追求體驗質量而使用PNG圖片來進行整體頁面的開發。
SVG:另外一種是SVG矢量圖,這種格式最大的好處就是放大縮小不會失真和細膩度極高同時文件相對較小和是代碼內嵌的圖片格式,能有條件的話盡可能使用這樣的圖片,當然這個也只能用于一些簡單的部件例如說圖標,按鈕等等一寫簡單的業務場景。
二、圖片處理
CSS sprite:目前來講spite還是比較常用的圖片整理方法,他的好處是將大大小小的圖片合并為一張大圖,再使用圖片定位來顯示對應的圖片,這樣可以減少頁面的請求,提高頁面加載速度。但也有個缺點就是既然是合成一張大圖,那么很多小圖片就依賴這一張圖片,如果這個圖片沒有加載出來那么整個頁面基本上就缺失了,但以現在的網絡來說,基本上也可以忽略這個問題了,現在基本上是4G網絡或者wifi不存在速度慢的情況。
Image-inline:使用BASE64格式嵌入到頁面中也是一個很好的辦法,減少htttp請求,但是實際的開發中一般也比較少這樣做,因為將圖片嵌入到HTML中其實到了后面也不好去維護,以我的開發經驗來說,一般是出現了沒辦法的情況下才使用BASE64的圖片格式。
例如在開發項目中,圖片資源一般都會放在不同域的地址中,使用CANVAS生成圖片的情況下,canvas.toDataUrl(…)會污染圖片的原來的地址,從而導致出現了跨域的問題,后端也不可因為這張圖片多帶帶生成的時候,這個時候用BASE64就是最簡單粗暴的解決方法。把圖片嵌入html就解決了跨域的情況。
壓縮:將圖片放在一些工具上批量進行壓縮。
一、網頁渲染的過程
網頁在加載的過程中,首先拿到的是一個HTML文本也可以說拿到的就是一串字符串,瀏覽器parse解析器要將這個字符串進行一系列的詞法分析,將每個標簽生成對應的一個token或者說是每個標簽對應的對象,然后從上到下解析這些token,接著就會一步步從上到下生成對應的DOM節點。
當然在詞法分析的過程中,就可以解析出link script標簽,對應的web資源就會被請求加載。JavsScript會被瀏覽器內核的V8引擎進行執行,而css就與html類似,他會被解析成CSSOM,然后HTML,CSSM,SCRIPT,解析完畢之后結合,生成Rander Tree 拿到的這些基本信息之后,接著進入layout也就是布局,最后進行渲染Paint。
二、 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用于需要加載大量圖片但可以根據用戶的操作來決定加載數量,目的是減少對服務器的請求和減少網絡流量的浪費,同時也提高了用戶的體驗度。例如一些電商的頁面展示商品,在瀏覽器滾動到的地方加載相應的數據,而不是一口氣把所有的數據全部列出來。在H5頁面中下拉刷新,上拉加載也是很常見的做法,當然這里由于IOS本身的瀏覽器特性也需要做一些相應的處理。
Preload用于一些需要注重用戶體驗和流暢的運行頁面交互的情況,在頁面加載的同時先把所有的數據全部加載好之后,再打開頁面。最常見的做法就是使用加載進度條,先把所有的靜態資源先用一個數組存放好,然后依次加載計算百分比,到達100%之后在走下一步操作。
重繪與回流我們先說一個幀的概念,目前,大部分的設備屏幕的的刷新頻率是60次/秒,也就是1000/60=1.6ms為一幀畫面。 瀏覽器要做任何的渲染那么他的這個渲染時間必須小于1.6ms或者盡量接近1.6ms,否則,就會出現卡頓的現象,影響用戶體驗。 假設現在瀏覽器渲染一個動畫的時間剛好為一幀,那么,這一幀的畫面這會首先會重新計算style(css/dom等)接著回流,更新tree,再進行重繪(painting),最后再進行圖層合并(Composite)。如下圖所示
一、重繪與回流:
前端性能優化最關鍵的就是減少頁面的重繪與回流。
回流(reflow)即當前頁面的布局和幾何屬性發生改變時,那么就會觸發回流的機制。
重繪( repaint)即render tree 的本身一些屬性更新了,但不影響整體的布局,只是改變了背景,顏色等等這就叫重繪。
二、優化:
減少重繪制與回流
避免使用會觸發回流的一些屬性,有些屬性會觸發回流的機制,例如: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 ,而且還需存儲它們,以便稍后在動畫中重用。不能隨意的創建圖層,一定要結合當前項目的情況去分析。因為創建一個新的層是有代價的,每創建一個新的渲染層,就意味著新的內存分配和更復雜的層管理。對于使用移動設備的用戶來說是一個很大的負擔。
一、存儲介質
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的資源
總結:頁面的優化方案需要根據當前項目的需求進行調整,達到實際體驗最佳的即可。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/62025.html
摘要:如下圖所示一重繪與回流前端性能優化最關鍵的就是減少頁面的重繪與回流。很明顯就是少了一步,這是因為把會觸發回流的屬性用替代,這樣就使渲染的過程減少了這一步,使渲染的時間減少從而提高性能。 我們今天來說說前端圖形渲染優化,因為我接下來的時間可能要開始研究webgl方面的東西,所以就在這里把之前做過的H5做一個總結,現同步發布于GERRY_BLOG,TiMiGerry-知乎,轉載請保留鏈接。...
摘要:在減少文件請求數量方面大致有以下三方面合并腳本文件合并樣式文件合并引用的圖片,使用雪碧圖。和的模塊管理不同,前者是基于靜態的,而后者是動態的。被打包文件的內容也已經被壓縮混淆,減少了加載文件的。 作者:劉軼斌,騰訊應用開發 工程師商業轉載請聯系騰訊WeTest獲得授權,非商業轉載請注明出處。 原文鏈接:http://wetest.qq.com/lab/view/345.html We...
摘要:摘要彈性裸金屬服務器的八大特性,總結相關特性。那么阿里云彈性裸金屬服務器神龍的表現呢在這里我們定義的彈性裸金屬服務器是一個新物種,它強調的是彈性,也就是通過技術創新,使得傳統裸金屬服務能夠做到和虛擬機一致的使用體驗和業務敏捷。 摘要: 彈性裸金屬服務器的八大特性,總結相關特性。那么阿里云彈性裸金屬服務器(神龍)的表現呢 在這里我們定義的彈性裸金屬服務器是一個新物種,它強調的是彈性,也就...
閱讀 2770·2021-10-11 11:08
閱讀 1488·2021-09-30 09:48
閱讀 1048·2021-09-22 15:29
閱讀 1036·2019-08-30 15:54
閱讀 976·2019-08-29 15:19
閱讀 526·2019-08-29 13:12
閱讀 3161·2019-08-26 13:53
閱讀 956·2019-08-26 13:28