今天主要分享幾點性能優化的實用方案,在前幾個月在公司實習的時候,經過回顧作的一些實戰項目總結出來了的,這對於剛剛接觸到前端性能問題的童鞋,但願可以給你提供一些入門型的指導。css
談起性能優化這個話題,實在是太大的,不只僅只是前端的性能優化,也是全鏈路的性能優化。前端、後臺、服務器、網絡等各個模塊的配合。前端
我在搞性能優化中,有些有關性能優化的點是《前端性能優化》的做者阿里的修言老哥給我稍做指點,加上實戰中的應用和反饋總結,才讓我得以有所感悟,值的去寫一寫。算法
今天所分享到的性能優化這個範圍也是根據我以前公司所在的一些業務和所使用的技術棧來展開聊聊的。有具體的優化場景,咱們再談起性能優化才以爲更加有意思。後端
面臨的技術棧和場景瀏覽器
若是不是對技術棧要求特別嚴格的公司來講,前端開發少不了這幾個技術棧。HTML5 + CSS3 + jQuery,有些公司還在用 JSP、.Net開發,針對這寫傳統技術,咱們須要使用一些特殊的手段去作優化。緩存
脫離了像 Vue 這種自己就是放棄傳統操做 DOM 的框架,只針對於傳統的性能優化,咱們如何下手?性能優化
PS:本文不談太過關於框架性能優化的內容,只從傳統的性能優化點出發。服務器
從定位問題開始網絡
有一次,線上項目出現問題,頁面某一部分渲染須要很長時間才顯示,究竟是哪出了問題。app
定位問題,是什麼致使了該頁面部份內容加載過慢,是數據的獲取過程,仍是頁面 JS 加載過程,仍是其餘渲染、繪製過程?
經過瀏覽器控制檯的俗稱神器的 Performance 定位問題。
這裏我以某網站爲項目對象,作個示範。
那個部分用時比較長,經過這個圖能夠分析到是哪一個環節出現了渲染時間比較長。
定位問題以後,開始作優化。可是作優化前提是具體一些優化的基礎內容,否則咱們根本不知道從哪裏着手開始優化。
數據請求時間過長
有時候咱們在作項目時,數據量太大,從服務器拿到數據這個過程時間太長。要想將這個時間變短,咱們須要減小請求的次數以及單次請求的時間。
對於減小請求次數,咱們能一次獲取的儘可能一次獲取到數據,而不是分爲屢次去請求,若是請求過多就會形成線程的阻塞。
咱們能夠結合具體業務進行適當的優化,將一些返回的【數據合併】,從而達到減小請求次數的目的。
可是單次請求的時間過長也是耗時間的,咱們傳輸大量的數據,只能將這些數據作壓縮處理,這樣單次請求就會變快。
還有其餘一些方案,好比懶加載,頁面給用戶呈現哪部份內容,就請求哪部份內容,而不是一股子氣所有請求回來。再好比,音頻走的是流文件,而不是把整段音頻請求回來纔給用戶播放,而是以流水的形式,邊播放,邊請求。
避免發生重繪和迴流
除此以外,最關鍵的就是頁面中的優化。首先回顧一下瀏覽器的工做原理。
動畫: 一個瀏覽器是如何工做的?
其中一個環節是渲染環節,將合成的渲染樹經過計算得出的像素位置和樣式,渲染到頁面中,最後呈獻給用戶。
雖然咱們在瀏覽器看到的頁面沒有感受,可是這個過程很是耗時的,尤爲是當咱們稍微改動頁面某一個元素的位置大小或者樣式的時候,都會致使整個頁面從新進行渲染。
若是頁面要渲染的內容不少,用戶每改動一個地方,就會形成所有渲染,性能很是耗時,最後致使用體驗很差,嚴重狀況形成頁面無響應。
咱們看到的不少文章中提到,咱們應該儘可能的避免頻繁的操做 DOM,從而避免發生頁面的迴流和重繪。
咱們發現 Vue 作了哪些改進,既然操做 DOM 致使性能不好,我就不操做 DOM 唄,因此 Vue 放棄了傳統的 DOM 操做,開啓了數據影響視圖模式。(PS:後期在分析 Vue 源碼文章中,我會主要分享這部分它內部如何巧妙實現的,而後帶你們本身手寫一個簡易版的 Vue)
可是很無奈,有些公司不用 Vue,這樣的公司太多了,領導表示就是不想用。就是想用傳統的 HTML5 + CSS3 + jQuery,那麼咱們對於優化又該怎麼作?
我我的又根據,作了一些性能優化總結。既然不讓用 Vue,那就決定的特定場景仍是涉及到操做 DOM 咯,雖然不能放棄傳統 DOM,那麼,我儘可能的減小操做 DOM 行不行,沒錯,按照這個方向去想,咱們能夠總結出如下幾點內容,小本本劃重點。
一、
分離讀寫操做
咱們頻繁的改變頁面樣式的位置以及大小會致使頁面的迴流和重繪,當代瀏覽器對這一點作了一點優化,當前行代碼若是改變了元素大小或者位置,不會當即致使頁面從新渲染,並且判斷下一行是否也是改變元素大小和樣式。
div.style.background = '#fff' div.style.color = 'red'
若是是,這些連續的代碼將阿計入到一個渲染隊列當中去,直到下一行代碼不是改變樣式的代碼,而後統一作一次頁面渲染,這樣大大減小了頁面的迴流和重繪。
咱們根據這個瀏覽器渲染隊列機制,咱們在寫代碼的時候,將讀寫屬性操做作分離,像下面這樣。
var curLeft = div.offsetLeft; var curTop = div.offsetTop ; div.style.left = curLeft + 1 + 'px' div.style.top = curTop + 1 + 'px'
若是不分離讀寫操做,而是將讀寫操做混起來寫,這樣會致使不斷的迴流和重繪。
二、
樣式集中改變
同理,在咱們用 JS 批量改變樣式的時候,要進行集中改變樣式。
box.style.cssText = 'width:200px;height:200px'; box.className = 'aa'
三、
緩存佈局信息
咱們一般會經過 JS 動態佈局的大小,咱們一般會這樣作。
// 如下會引起兩次迴流 div.style.left = div.offsetLeft + 1 + 'px' div.style.top= div.offsetTop + 1 + 'px'
可是按照咱們上邊所總結的,這樣子作很差,由於會致使屢次重繪。
若是咱們這樣,先把獲取的佈局信息經過變量進行緩存,而後再統一改變樣式。
// 修改成:只會觸發一次迴流 var curLeft = div.offsetLeft; var curTop = div.offsetTop ; div.style.left = curLeft + 1 + 'px' div.style.top = curTop + 1 + 'px'
四、
元素批量修改
若是咱們進行批量的改變元素,咱們能夠單獨拿出來改變完,而後再放回頁面中,這樣,你不管改變多少次,只引起一次迴流。
// 文檔碎片 let frg = document.createDocumentFragment(); for(let i = 0;i < 5;i++){ let newLi = document.createElement('li'); newLi.innerHTML = i; frg.appendChild(newLi); }
除此以外,咱們也可使用字符窗拼接的方式。
// 字符串拼接 for(let i= 0;i< 5;i++){ str += `<li>${i}</li>` } box.innerHTML = str
五、
動畫優化
有時候咱們想使用動畫,動畫會頻繁的改變元素的狀態,致使不斷的迴流和重繪。
因此咱們爲了可以使性能更佳,咱們動畫效果應用到 position 屬性爲 absolute 或 fixed 上(脫離文檔流)。
雖然會在一個新的平面,也會引起迴流,可是不會影響到其餘的元素,這樣看起來性能更好。
六、
開啓 CSS 硬件加速(GPU加速)
CSS3 改變樣式能用 transform 的局部用其餘元素,由於 transform 開啓了硬件加速,規避了【迴流】和【重繪】。
box.style.transform = 'translateX(200px)'
硬件加速的其餘屬性:transform \ opacity \ filters。因此能用這些屬性儘可能用這些屬性去改變元素。
七、
犧牲平滑速度換取速度
每次動畫移動一個像素,CPU 佔用率 100%,動畫看起來有些跳動,由於瀏覽器正在與迴流做鬥爭。
若是每次移動 3 像素可能看起來平滑度下降了,可是不會致使 CPU 在較慢的機器中抖動。
小結
以上是對於一些傳統網頁存在的性能問題,總結的幾點優化方案。可是隻靠這幾點仍是遠遠不夠的。
開篇提到過,性能優化不只僅是前端或者是後端工程師的事情,並且全鏈路的性能優化。
不管是性能優化仍是算法、網絡等其餘方面,都應該造成一種屬於本身的思想知識體系。經過不斷的遇到問題,解決問題,而後不斷完善這個體系,這纔是咱們最終要追求的一個小目標。