摘要:語句會使得局部變量位于作用域第二層,會使性能下降,所以應避免使用。使用事件委托來減少事件處理器的數量。把最可能出現的條件放在首位。在進行優化時,要弄清楚性能瓶頸,然后對癥優化。新看到一篇很棒的文章前端性能優化備忘錄如有不對,歡迎指正。
春節在家,把《高性能的JavaScript》刷了一遍,受益匪淺。本著每看完一本書都要做讀書筆記的習慣,將書中的知識點總結一下。
JavaScript加載和執行由于不同瀏覽器使用的JavaScript引擎不同,因此對JavaScript的優化也不盡相同。也因此,有些方法在IE上可能性能相差很大,但在chrome上相差無幾,也甚至某些方法在IE上最快,但在chrome上卻并不是最優的方案,所以,對性能有極致要求的應用,應考慮你的產品使用者最常用的瀏覽器。當然,下面提到的優化方法都是通用法則或者對大多數瀏覽器都友好的方法。
JavaScript的下載和執行會阻塞用戶界面的繪制和其他資源的下載
優化方法:1.阻塞式腳本:合并文件(減少http請求),將script標簽放在body尾部(減少頁面css,html的下載阻塞,減少界面的空白時間(瀏覽器在解析到script標簽之前,不會渲染頁面的任何部分))
目前流行的構建工具,如webpack,gulp,都有打包、合并文件的功能。
2.無阻塞式腳本:延遲腳本和動態腳本均不阻塞,即下載過程不阻塞其他進程
延遲腳本:
defer和async屬性:都是并行下載,下載過程不阻塞,區別在于執行時機,async是下載完成后立即執行;defer是等頁面加載完成后再執行。defer僅當src屬性聲明時才生效(HTML5的規范)
動態腳本:
動態添加script標簽,返回的代碼通常會立刻執行,所以,為了確保腳本下載完成且準備就緒后才執行,須偵聽load事件。將script添加到head中比添加到body中更保險。
//動態添加腳本,當腳本下載完成且準備就緒后執行回調函數。(這也是推薦的無阻塞的方法) function loadScript(url,callback){ var script=document.creatElement("script"); script.type="text/javascript"; if(script.readyState){ //IE script.onreadystatechange=function(){ if(script.readyState == "loaded" || script.readyState == "complete"){ script.onreadystatechange=null; callback(); } } }else{ //非IE script.onload=function(){ callback(); } } script.src=url; document.getElementsByTagName("head")[0].appendChild(script); }數據存取
將全局變量存儲到局部變量中:因為全局變量總是存在于執行環境作用域鏈的最末端,所以,訪問全局變量是最慢的,訪問局部變量是最快的。尤其是對于未優化過的JavaScript引擎。
在JavaScript中,只有2個語句可以在執行時臨時改變作用域鏈:with語句和try-catch的catch子句。with語句會使得局部變量位于作用域第二層,會使性能下降,所以應避免使用。try-catch權衡使用(因為可預測的錯誤說明代碼有問題,應及早修復)。
盡量避免使用with,try-catch,eval等動態作用域語句,因為JavaScript引擎無法通過靜態分析的方法進行優化。
閉包會影響性能(作用域鏈加深)和可能導致內存泄漏(IE中)
總結:使用對象字面量代替對象
使用局部變量存儲全局變量和對象成員
盡量不用with,eval語句,try-catch的catch子句要謹慎使用
嵌套越深,性能越差,盡量少用。
DOM編程DOM和JavaScript是2個獨立的功能,只通過API連接,用JavaScript操作DOM天生就慢,所以應盡量減少用JavaScript操作DOM。
原則:1.減少訪問DOM的次數,把運算盡量留在ECMAScript這一端處理。
2.innerHTML在絕大多數瀏覽器中比原生DOM方法要快(最新版的chrome除外),推薦使用。
3.用element.cloneNode()代替document.createElement(),稍快一些。
4.緩存HTML集合的length.
//這會是一個死循環,因為取HTML集合的length會重復執行查詢的過程。 var addDivs=document.getElementsByTagName("div"); for(var i=0,len=addDivs.length;i5.使用children代替childNodes,因為childNodes會包含文本節點(空格)和注釋節點,還需要自己額外過濾這些節點,children已經幫我們過濾掉這些節點了,而且使用的過濾方法效率很高。
6.原生選擇器API:querySelectorAll()和querySelector() ,IE8及以上支持
querySelectorAll()返回的是個nodelist(也是類數組),不是HTML集合(與getElenmentsByTagName等不同)。
7.減少重繪和重排:
在修改樣式的過程中,最好避免使用下面的屬性,因為它們會刷新渲染隊列,盡量少查詢下列屬性,可以用局部變量緩存結果。offsetTop,offsetLeft,offsetWidth,offsetHeight, scrollTop,scrollLeft,scrollWidth,scrollHeight clientTop,clientLeft,clientWidth,clientHeight getComputedStyle() (currentStyle in IE)8.合并多次對DOM和樣式的修改:
el.style.cssText+=";border-left:2px;"; JavaScript改變class9.批量修改DOM時,使用document fragment:文檔片段是一個輕量級的document對象,它本身就是為了更新和移動節點設計的。
var fragement=document.createDocumentFragment(); var li=document.createElement("li"); fragement.appendChild(li); document.body.appendChild(fragement);10.動畫中使用絕對定位,使用拖放代理。
11.使用事件委托來減少事件處理器的數量。ps:個人覺得,原生方法和庫封裝的方法并不沖突,應根據實際情況和個人的技能掌握情況選擇最合適的方法。
算法和流程控制for...in的循環性能最差(因為它需要搜索實例和原型上的所有屬性),除非,你需要遍歷一個屬性數量未知的對象,否則不要使用它。
更不要用它遍歷數組成員。其余的循環性能都差不多。倒序循環,把減法操作放到控制條件中,例如:k--,這樣只是比較“它是true嗎?”速度更快。
forEach()比數組循環慢,如果對性能有極致要求,還是用數組循環好。
當判斷值多于2個時,使用switch,否則用if-else (數量少時,性能差別不大,可根據個人喜好使用)。若判斷值很多,且沒有什么復雜的操作,可以用數組代替switch。
在JavaScript中,switch使用全等操作符,不會發生類型轉換的損耗。把最可能出現的條件放在首位。
調用棧溢出錯誤基本都是由遞歸導致的:不正確的終止條件;包含了太多遞歸,超過了瀏覽器的調用棧限制。把遞歸算法改用迭代算法實現是避免調用棧溢出錯誤的解決方法之一。
緩存:避免重復性工作,手動實現緩存(Vue源碼中就有很多緩存)
function memfactorial(n){ if(!memfactorial.cache){ memfactorial.cache={ "0":1, "1":1 } } if(!memfactorial.cache.hasOwnProperty(n)){ memfactorial.cache[n]=n* memfactorial(n-1); } return memfactorial.cache[n]; }字符串和正則表達式字符串拼接推薦用+ +=,推薦寫法:str=str+"one"+"two";(將str寫在左側)
書上說:在大多數瀏覽器中,Array.prototype.join()比其他字符串連接方法更慢,但在IE7及早期的瀏覽器中,在合并大量字符串時是最高效的途徑。
每個瀏覽器都有它自己的正則表達式引擎,它們有著各自的優勢。
提高正則表達式效率的方法關注如何讓匹配更快失敗
正則表達式以簡單,必需的字元開始:例如:起始標記是^,特定字符串,[a-z]或者d等,避免以分組或選擇字元開頭,避免/one|two/頂層分支。
減少分支數量,縮小分支范圍:例如:將cat|bat 替換為:[cb]at ;將red|read 替換為:rea?d 將red|raw 替換為:r(?:ed|aw) 將(.|r|n)替換為:[sS]。
當分支必不可少時,將常用分支放到前面。
使用非捕獲組
合理使用捕獲:如果需要引用匹配的一部分,應用捕獲,然后引用那部分
暴露必須的字元:用/^(ab|cd)/代替/(^ab|^cd)/
使用合適的量詞:貪婪和惰性量詞的匹配過程不一樣,視情況選擇使用。
將正則表達式賦值給變量(以避免對正則重新編譯)并重用它們。
將復雜的正則拆分為簡單的片段:如果太復雜,可以先用條件判斷分割
//去除字符串首尾空格的方法,推薦寫法 if(!String.prototype.trim){ //防止覆蓋原生方法 String.prototype.trim=function(){ return this.replace(/^s+/,"").replace(/s+$/,""); } }其他盡管正則很強大,但也不是任何時候都要用正則。對于字面量字符串的操作,字符串原生的方法就很快,例如:indexOf,slice,substring等。
建議定時器最小延遲時間是25ms.小于10ms時,各瀏覽器表現不一致。
多個定時器時,用setInterval()代替多個setTimeout()
使用動態腳本注入(json-p),要小心第三方域代碼的安全性。不要把敏感信息編碼在json-p中。即便是帶有隨機URL或做了cookie判斷。
圖片信標:只是用來發送簡單數據
//只是創建一個Image對象,并不把img插入DOM中。 (new Image()).src=url+params.join("&");盡可能使用JOSN.parse()解析json字符串,該方法可以捕獲json字符串中的詞法錯誤,并允許傳入一個函數用來過濾或轉換解析結果。
ajax類庫的局限:ajax類庫為了兼容瀏覽器,所以不能訪問XMLHttpRequests的完整功能。例如不能直接訪問readystatechange事件,所以要了解原生的寫法。
所以,要知道何時使用成熟的類庫,何時編寫自己的底層代碼。縮短頁面的加載時間,頁面主要內容加載完成后,再用ajax獲取那些次要的文件。(首頁優化)
通過正確設置響應頭來緩存JavaScript文件。
使用位操作,速度快。
i%2 //可以改寫成位運算 &1 : if(i&1){ //奇數 }else{ //偶數 } //位掩碼:后臺常用的按位打標, var ops=op_a | op_b | op_c; if(ops & op_a){ //op_a存在 }個人感想性能提升有多方面:客戶端性能,網絡情況,服務器性能,在具體解決及分析問題時,要從各個方面考慮,JavaScript代碼質量,http請求數也只是其中一部分而已,要全面考慮。在進行優化時,要弄清楚性能瓶頸,然后對癥優化。
新看到一篇很棒的文章:
前端性能優化備忘錄:https://www.w3ctech.com/topic...ps:如有不對,歡迎指正。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/81436.html
摘要:特意對前端學習資源做一個匯總,方便自己學習查閱參考,和好友們共同進步。 特意對前端學習資源做一個匯總,方便自己學習查閱參考,和好友們共同進步。 本以為自己收藏的站點多,可以很快搞定,沒想到一入匯總深似海。還有很多不足&遺漏的地方,歡迎補充。有錯誤的地方,還請斧正... 托管: welcome to git,歡迎交流,感謝star 有好友反應和斧正,會及時更新,平時業務工作時也會不定期更...
摘要:歡迎來我的個人站點性能優化其他優化瀏覽器關鍵渲染路徑開啟性能優化之旅高性能滾動及頁面渲染優化理論寫法對壓縮率的影響唯快不破應用的個優化步驟進階鵝廠大神用直出實現網頁瞬開緩存網頁性能管理詳解寫給后端程序員的緩存原理介紹年底補課緩存機制優化動 歡迎來我的個人站點 性能優化 其他 優化瀏覽器關鍵渲染路徑 - 開啟性能優化之旅 高性能滾動 scroll 及頁面渲染優化 理論 | HTML寫法...
摘要:即使這些動畫庫使用轉換,合成屬性和,但是它們仍然運行在的主線程上。另一方面,動畫和轉換會在主線程中運行,如果能夠高效執行,則能避免重新布局重排的情況出現。是一個即將到來的功能集,它能夠脫離主線程執行高性能的動畫。 JavaScript 作為當前最為常見的直譯式腳本語言,已經廣泛應用于 Web 應用開發中。為了提高Web應用的性能,從 JavaScript 的性能優化方向入手,會是一個很...
閱讀 2847·2021-09-27 13:35
閱讀 624·2021-09-23 11:22
閱讀 2892·2019-08-30 15:54
閱讀 1612·2019-08-29 16:27
閱讀 2468·2019-08-29 15:05
閱讀 2350·2019-08-23 18:11
閱讀 3523·2019-08-23 16:32
閱讀 2941·2019-08-23 14:56