目錄
強制快取
協商快取
減少http請求
代码性能
首頁 web前端 js教程 Js前端效能優化總結

Js前端效能優化總結

Feb 28, 2018 pm 01:42 PM
javascript 最佳化 總結

最好的資源最佳化就是不載入資源。緩存也是最見效的優化手段。說實話,雖然說客戶端快取發生在瀏覽器端,但快取主要還是服務端來控制,與我們前端關係並不是很大。但還是有必要了解一下。

快取包含服務端快取和客戶端緩存,本文只談客戶端快取。所謂客戶端快取主要是http快取。 http快取主要分為強制快取和協商快取。

強制快取

  • Expires(http1.0)

在http1.0中使用Expires來做強制快取。 Exprires的值為服務端傳回的資料到期時間。當再次請求時的請求時間小於返回的此時間,則直接使用快取資料。但由於服務端時間和客戶端時間可能有誤差,這也將導致快取命中的誤差。

  • Cache-Control

Cache-Control有很多屬性,不同的屬性代表的意義也不同。

  1. private:客戶端可以快取

  2. #public:客戶端和代理伺服器都可以快取

  3. max-age=t:快取內容將在t秒後失效

  4. no-cache:需要使用協商快取來驗證快取資料

  5. no-store:所有內容都不會快取。

協商快取

瀏覽器第一次要求資料時,伺服器會將快取標識與資料一起回應給客戶端,客戶端將它們備份到快取中。再次請求時,客戶端會將快取中的識別傳送給伺服器,伺服器根據此標識判斷。若未失效,返回304狀態碼,瀏覽器拿到此狀態碼就可以直接使用快取資料了。

  • Last-Modified

伺服器在回應請求時,會告訴瀏覽器資源的最後修改時間

  • if-Modified-Since

瀏覽器再次請求伺服器的時候,請求頭會包含此字段,後面跟著在快取中獲得的Last-Modified(最後修改時間)。服務端收到此要求頭髮現有if-Modified-Since,則與被要求資源的最後修改時間進行對比,如果大於被要求資源最後修改時間則返回304,瀏覽器從快取獲取資源。如果小於被要求資源最後修改時間,則傳回200,並傳回最新資源,瀏覽器從服務端取得最新的資源,並快取。

  • Etag

伺服器產生的每個資源的唯一識別字串

  • If -None-Match

再次請求伺服器時,瀏覽器的請求封包頭會包含此字段,後面的值為在快取中取得的識別。伺服器接收到次訊息後發現If-None-Match則與被要求資源的唯一識別進行比較。如果相同,表示資源沒有被修改過,返回304,瀏覽器從快取取得資源,如果不同說明資源被修改過,則傳回200,並傳回最新資源,瀏覽器從服務端取得最新資源,並快取。

Last-Modified與ETag是可以一起使用的,伺服器會優先驗證ETag,一致的情況下,才會繼續比對Last-Modified,最後才決定是否回傳304。

如果使用前端打包工具,可以在打包檔案時候在為檔案新增版本號碼或hash值,同樣可以區分資源是否過期。

減少http請求

  • 使用CDN託管靜態資源

  • 可以藉助gulp、webpack等打包工具對js、css等檔案合併與壓縮

  • 圖片懶載入、按需加載,當捲動到圖片視覺區域才去載入圖片

  • ##小圖片且基本上不會改變的圖片使用base64編碼傳輸。 base64不要濫用,即使小圖片經過base64編碼之後也會產生很長的字串,如果濫用base64反而會適得其反

  • 雪碧圖,這個也是針對基本不會更改的圖片才使用雪碧圖,因為如果一張圖片修改,會導致整個雪碧圖重新生成,如果亂用也會適得其反。

減少http請求資源體積

  • 借助webpack、gulp等工具壓縮資源

  • 服務端開啟gzip壓縮(壓縮率非常可觀,一般都在30%之上)

  • 如果有用打包工具,打包優化要做好,公共資源、提取第三方程式碼、不需要打包的庫...

渲染優化

讀過前面js運行機制的應該知道,從瀏覽器輸入url,到頁面出現在螢幕上,都發生了哪些事(tcp握手、dns解析等不在認知範圍)。
  • FPS 16ms 小於10ms完成最好  Google devtool 查看影格率

如果瀏覽器FPS到達60,就會顯得比較流暢,大多數顯示器的刷新頻率是60Hz,瀏覽器會自動依照這個頻率刷新動畫。
依照FPS等於60來計算,平均一幀的時間為1000ms/60 = 16.7ms,所以每次渲染時間不能超過16ms,如果超過這個時間就會出現丟幀、卡頓現象。

可以在chrome瀏覽器開發者工具中的Timeline中查看更新率,可以查看所有幀率耗時情況以及某一幀的執行情況。 Timeline的使用教學:https://segmentfault.com/a/11...

為了確保正常的FPS,有些渲染效能最佳化還是有必要的。以下所介紹的都是有關渲染優化的策略。

  • 盡量使用css3來做動畫

#總所周知,css的效能要比js快,所以能使用css,盡量不用js來實現

  • 避免使用setTimeout或setInterval,盡量使用requestAnimationFrame來做動畫或高頻Dom操作。

因為setTimeout和setInterval無法保證callback函數的執行時機,很可能在幀結束的時候執行,從而導致丟幀,但是requestAnimationFrame可以保證callback函數在每幀動畫開始的時執行
requestAnimationFrame的中文MDN位址:https://developer.mozilla.org...

  • 複雜的運算運算使用Web Workers

#如果有需要複雜的資料操作,例如對一個有一個元素的陣列遍歷求和,那麼Web Workers在適合不過了。

Web Workers可以讓JavaScript腳本在後台執行緒(類似建立一個子執行緒),而後台執行緒不會影響到主執行緒中的頁面。不過,使用Web Workers建立的執行緒是不能操作DOM樹。
有關Web Workers的更多可以查看MDN詳解:https://developer.mozilla.org...

  • css放在頭部,js放在尾部。

讀過前面js運作機制的應該知道頁面渲染是怎樣一個過程,不再贅述了。 css放在頭部會避免生成html樹之後重新佈局的閃屏現象,js一般對頁面的影響較大,一般放在尾部最後執行。

  • 事件防手震(debounce)與節流(throttle)

針對高頻觸發的事件(mousemove、scroll)等事件,如果不加以控制會在短時間內觸發很多事件。

函數防手震是指頻繁觸發的情況下,只有足夠的空閒時間,才會執行程式碼一次。場景:註冊時郵箱的輸入框,隨著使用者的輸入,即時判斷郵箱格式是否正確,當第一次輸入事件觸發,設定定時:在800ms之後執行檢查。假如只過了100ms,上次的定時還沒執行,此時清除定時,重新定時800ms。直到最近一次的輸入,後面沒有緊鄰的輸入了,這最近一次的輸入定時計時結束,終於執行了檢查代碼。

const filter  = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;  
$("#email").on("keyup",checkEmail());  
function checkEmail(){  
    let timer=null;  
    return function (){  
        clearTimeout(timer);  
        timer=setTimeout(function(){  
            console.log('执行检查');  
        },800);  
    }  
}
登入後複製

函數節流是指一定時間內js方法只跑一次。就是本來一秒要執行100次的變成一秒執行10次。
場景:函數節流應用的實際場景,多數在監聽頁面元素滾動事件的時候會用到。

var canRun = true;
document.getElementById("throttle").onscroll = function(){
    if(!canRun){
        // 判断是否已空闲,如果在执行中,则直接return
        return;
    }

    canRun = false;
    setTimeout(function(){
        console.log("函数节流");
        canRun = true;
    }, 300);
};
登入後複製
  • Dom操作

前端開發人員都知道Do操作是非常耗時的(曾經親測過30*30的表格遍歷新增樣式)。所以盡量避免頻繁的Dom操作,如果避免不了就盡量對DOm操作做優化。

1.:缓存Dom查询,比如通过getElementByTagName('p')获取Dom集,而不是逐个获取。

2: 合并Dom操作,使用createDocumentFragment()
登入後複製
    var frag = document.createDocumentFragment()
    for (i<10) {
        var li = document.createElement(&#39;li&#39;)
        frag.appendChild(li)
    }
    document.body.appendChild(frag)
登入後複製
 3: 使用React、Vue等框架的虚拟dom(原理目前还不明白),可以更快的实现dom操作。
登入後複製
  • 盡量避免重繪(rePaint)和回流(reFlow)

如果使用js修改元素的顏色或背景色就會觸發重繪,重繪的開銷還是比較昂貴的,因為瀏覽器會在某一個DOM元素的視覺效果改變後去check這個DOM元素內的所有節點。

如果修改元素的尺寸和位置就會發生回流,回流開銷更大,它會在某一個DOM元素的位置改變後觸發,而且它會重新計算所有元素的位置和在頁面中的佔有的面積,這樣的話將會引起頁面某一個部分甚至整個頁面的重新渲染。

  • css3硬體加速

瀏覽器渲染時,會分成兩個圖層:普通圖層和複合圖層。

普通文件流內可以理解為一個複合圖層,absolute、fixed佈局雖然可以脫離普通文檔流,但它仍然屬於普通圖層,不會啟動硬體加速。上面說的重繪(rePaint)和回流(reFlow)說的就是普通圖層上的重繪和回流。

複合圖層會啟動硬體加速。和普通圖層不在同一個圖層,所以複合圖層不會影響普通圖層,如果一個元素被提升到複合圖層,再操作該元素時,就不會引起普通圖層的重繪和回流,從而提升渲染效能。

如何啟動硬體加速:

1.使用translate3d和translateZ

webkit-transform: translateZ(0);
-moz-transform: translateZ(0);
-ms-transform: translateZ(0);
-o-transform: translateZ(0);
transform: translateZ(0);

webkit-transform: translate3d(0,0,0);
-moz-transform: translate3d(0,0,0);
-ms-transform: translate3d(0,0,0);
-o-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
登入後複製

2.使用opacity
需要动画执行的过程中才会创建合成层,动画没有开始或结束后元素还会回到之前的状态

3.使用will-chang属性
这个属性比较不常用,一般配合opacity与translate使用

针对webkit浏览器,启用硬件加速有些时候可能会导致浏览器频繁闪烁或抖动,可以使用下面方法消除:

-webkit-backface-visibility:hidden;
-webkit-perspective:1000;
登入後複製
如果使用硬件加速,请使用z-index配合使用, 因为如果这个元素添加了硬件加速,并且index层级比较低, 那么在这个元素的后面其它元素(层级比这个元素高的,或者相同的,并且releative或absolute属性相同的), 会默认变为复合层渲染,如果处理不当会极大的影响性能
  • 避免强制同步布局和布局抖动

浏览器渲染过程为:js/css(javascript) > 计算样式(style) > 布局(layout) > 绘制(paint) > 渲染合并图层(Composite)

JavaScript:JavaScript实现动画效果,DOM元素操作等。
Style(计算样式):确定每个DOM元素应该应用什么CSS规则。
Layout(布局):计算每个DOM元素在最终屏幕上显示的大小和位置。
Paint(绘制):在多个层上绘制DOM元素的的文字、颜色、图像、边框和阴影等。
Composite(渲染层合并):按照合理的顺序合并图层然后显示到屏幕上。

在js中如果读取style属性的某些值就会让浏览器强行进行一次布局、计算,然后再返回值,比如:

offsetTop, offsetLeft, offsetWidth, offsetHeight

scrollTop/Left/Width/Height

clientTop/Left/Width/Height

width,height

请求了getComputedStyle(), 或者 IE的 currentStyle
登入後複製

所以,如果强制浏览器在执行JavaScript脚本之前先执行布局过程,这就是所谓的强制同步布局。
比如下面代码:

requestAnimationFrame(logBoxHeight);

// 先写后读,触发强制布局
function logBoxHeight() {
    // 更新box样式
    box.classList.add('super-big');

    // 为了返回box的offersetHeight值
    // 浏览器必须先应用属性修改,接着执行布局过程
    console.log(box.offsetHeight);
}

// 先读后写,避免强制布局
function logBoxHeight() {
    // 获取box.offsetHeight
    console.log(box.offsetHeight);

    // 更新box样式
    box.classList.add('super-big');
}
登入後複製

在JavaScript脚本运行的时候,它能获取到的元素样式属性值都是上一帧画面的,都是旧的值。因此,如果你在当前帧获取属性之前又对元素节点有改动,那就会导致浏览器必须先应用属性修改,结果执行布局过程,最后再执行JavaScript逻辑。

如果连续多次强制同步布局,就会导致布局抖动
比如下面代码:

function resizeAllParagraphsToMatchBlockWidth() {
  for (var i = 0; i < paragraphs.length; i++) {
    paragraphs[i].style.width = box.offsetWidth + &#39;px&#39;;
  }
}

作者:SylvanasSun
链接:https://juejin.im/post/59da456951882525ed2b706d
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
登入後複製

我们知道浏览器是一帧一帧的刷新页面的,对于每一帧,上一帧的布局信息都是已知的。
强制布局就是使用js强制浏览器提前布局,比如下面代码:

// bed  每次循环都要去获取left ,就会发生一次回流
function logBoxHeight() {
  box.style.left += 10
  console.log(box.style.left)
}

// goog 
var width = box.offsetWidth;

function resizeAllParagraphsToMatchBlockWidth() {
  for (var i = 0; i < paragraphs.length; i++) {
    // Now write.
    paragraphs[i].style.width = width + &#39;px&#39;;
  }
}
登入後複製
  • DOMContentLoaded与Load

DOMContentLoaded 事件触发时,仅当DOM加载完成才触发DOMContentLoaded,此时样式表,图片,外部引入资源都还没加载。而load是等所有的资源加载完毕才会触发。

1. 解析HTML结构。
2. 加载外部脚本和样式表文件。
3. 解析并执行脚本代码。
4. DOM树构建完成。//DOMContentLoaded
5. 加载图片等外部文件。
页面加载完毕。//load
登入後複製
  • 视觉优化

等待加载时间可以合理使用loading gif动图一定程度上消除用户等待时间的烦躁感

代码性能

代码对性能的影响可大可小,但是养成一个良好的写代码习惯和高质量的代码,会潜移默化的提高性能,同时也能提高自己的水平。废话不多说,直接看我总结的部分要点(因为这一部分知识点太多,需要大家写代码的时候多多总结)。

  • 避免全局查找

访问局部变量会比访问全局变量快,因为js查找变量的时候现在局部作用局查找,找不到在逐级向上找。

// bad
function f () {
    for (...){
        console.log(window.location.href)
    }
}

//good
function f () {
    var href = window.location.href
    for (...){
        console.log(href)
    }
}
登入後複製
  • 循环技巧

// bed 
for(var i = 0; i < array.length; i++){
    ....
}
// good
for(var i = 0, len = array.length; i < len; i++){
    ....
}
// 不用每次查询长度
登入後複製
  • 不要使用for in 遍历数组

for in是最慢的,其他的都差不多,其中直接使用for循环是最快的。for in只是适合用来遍历对象。

  • 使用+''代替String()吧变量转化为字符串

var a = 12
//bad
a = String(a)

// good
var a = 12
a = a + &#39;&#39;
登入後複製

这个还有很多类似的,比如使用*1代替parseInt()等都是利用js的弱类型,其实这样对性能提升不是很大,网上有人测试过,进行十几万次变量转换,才快了零点几秒。

  • 删除dom

删除dom元素要删除注册在该节点上的事件,否则就会产生无法回收的内存,在选择removeChild和innerHTML=''二者之间尽量选择后者,据说removeChild有时候无法有效的释放节点(具体原因不明)

  • 使用事件代理处理事件

任何可以冒泡的事件都可以在节点的祖先节点上处理,这样对于子节点需要绑定相同事件的情况就不用分别给每个子节点添加事件监听,而是都提升到祖先节点处理。

  • 通过js生成的dom对象必须append到页面中

在IE下,js创建的额dom如果没有添加到页面,这部分内存是不会被回收的

  • 避免与null比较

可以使用下面方法替换与null比较
1.如果该值为引用类型,则使用instanceof检查其构造函数
2.如果该值为基本类型,使用typeof检查类型

  • 尽量使用三目运算符代替if else

if(a>b){num = a}
else{num = b}

// 可以替换为
num = a > b ? a : b
登入後複製
  • 当判断条件大于3中情况时,使用switch代替if

因为switch的执行速度比if要快,也别是在IE下,速度大约是if的两倍。

相关推荐:

CSS解读前端性能优化的具体分析

在HTML5中如何提高网站前端性能的示例代码分析

web前端性能优化方法


以上是Js前端效能優化總結的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

解碼Laravel效能瓶頸:優化技巧全面揭秘! 解碼Laravel效能瓶頸:優化技巧全面揭秘! Mar 06, 2024 pm 02:33 PM

解碼Laravel效能瓶頸:優化技巧全面揭秘! Laravel作為一個受歡迎的PHP框架,為開發者提供了豐富的功能和便利的開發體驗。然而,隨著專案規模增加和訪問量增加,我們可能會面臨效能瓶頸的挑戰。本文將深入探討Laravel效能最佳化的技巧,幫助開發者發現並解決潛在的效能問題。一、資料庫查詢優化使用Eloquent延遲載入在使用Eloquent查詢資料庫時,避免

C++ 程式最佳化:時間複雜度降低技巧 C++ 程式最佳化:時間複雜度降低技巧 Jun 01, 2024 am 11:19 AM

時間複雜度衡量演算法執行時間與輸入規模的關係。降低C++程式時間複雜度的技巧包括:選擇合適的容器(如vector、list)以最佳化資料儲存和管理。利用高效演算法(如快速排序)以減少計算時間。消除多重運算以減少重複計算。利用條件分支以避免不必要的計算。透過使用更快的演算法(如二分搜尋)來優化線性搜尋。

深度解讀:為何Laravel速度慢如蝸牛? 深度解讀:為何Laravel速度慢如蝸牛? Mar 07, 2024 am 09:54 AM

Laravel是一款廣受歡迎的PHP開發框架,但有時候被人詬病的就是其速度慢如蝸牛。究竟是什麼原因導致了Laravel的速度不盡人意呢?本文將從多個面向深入解讀Laravel速度慢如蝸牛的原因,並結合具體的程式碼範例,幫助讀者更深入地了解此問題。 1.ORM查詢效能問題在Laravel中,ORM(物件關係映射)是一個非常強大的功能,可以讓

Golang的gc優化策略探討 Golang的gc優化策略探討 Mar 06, 2024 pm 02:39 PM

Golang的垃圾回收(GC)一直是開發者關注的熱門話題。 Golang作為一門快速的程式語言,其自帶的垃圾回收器能夠很好地管理內存,但隨著程式規模的增大,有時會出現一些效能問題。本文將探討Golang的GC最佳化策略,並提供一些具體的程式碼範例。 Golang中的垃圾回收Golang的垃圾回收器採用的是基於並發標記-清除(concurrentmark-s

Laravel效能瓶頸揭秘:優化方案大揭秘! Laravel效能瓶頸揭秘:優化方案大揭秘! Mar 07, 2024 pm 01:30 PM

Laravel效能瓶頸揭秘:優化方案大揭秘!隨著網路技術的發展,網站和應用程式的效能優化變得愈發重要。作為一款流行的PHP框架,Laravel在開發過程中可能會面臨效能瓶頸。本文將探討Laravel應用程式可能遇到的效能問題,並提供一些最佳化方案和具體的程式碼範例,讓開發者能夠更好地解決這些問題。一、資料庫查詢最佳化資料庫查詢是Web應用中常見的效能瓶頸之一。在

優化WIN7系統開機啟動項目的操作方法 優化WIN7系統開機啟動項目的操作方法 Mar 26, 2024 pm 06:20 PM

1.在桌面上按組合鍵(win鍵+R)開啟運行窗口,接著輸入【regedit】,回車確認。 2.開啟登錄編輯程式後,我們依序點選展開【HKEY_CURRENT_USERSoftwareMicrosoftWindowsCurrentVersionExplorer】,然後看目錄裡有沒有Seri​​alize項,如果沒有我們可以點選右鍵Explorer,新建項,並將其命名為Serialize。 3.接著點選Serialize,然後在右邊窗格空白處點選滑鼠右鍵,新建一個DWORD(32)位元值,並將其命名為Star

解決 PHP 函數效率低的方法有哪些? 解決 PHP 函數效率低的方法有哪些? May 02, 2024 pm 01:48 PM

PHP函數效率最佳化的五大方法:避免不必要的變數複製。使用引用以避免變數複製。避免重複函數呼叫。內聯簡單的函數。使用數組優化循環。

優化 Discuz 線上人數顯示的方法分享 優化 Discuz 線上人數顯示的方法分享 Mar 10, 2024 pm 12:57 PM

優化Discuz線上人數顯示的方法分享Discuz是一款常用的論壇程序,透過優化線上人數的顯示,可以提升使用者體驗和網站的整體效能。本文將分享一些優化線上人數顯示的方法,並提供具體的程式碼範例供您參考。一、利用快取在Discuz的線上人數顯示中,通常需要頻繁地查詢資料庫來獲取最新的線上人數數據,這會增加資料庫的負擔和影響網站的效能。為了解決這個問題,我

See all articles