摘要:而像和會增加作用域鏈的長度,所以也會降低性能。但是用獲取一些屬性時,會不由自主地強迫隊列中的所有渲染事件前不完成。在條件增加時,所帶來的性能負擔要高于,因此建議使用。它代價昂貴,且容易失控。
正巧看到在送書,于是乎找了找自己博客上記錄過的一些東西來及其無恥的蹭書了~~~
小廣告:更多內容可以看我的博客
以下內容均來自《高性能JavaScript》
JavaScript文件加載管理瀏覽器中的JavaScript代碼是一個棘手的問題,因為代碼執行會阻塞瀏覽器,比如界面繪制。每次遇到標簽,瀏覽器都會停下來等待代碼下載并執行,然偶再繼續處理其他部分。我們可以通過如下幾種方法來減少JavaScript文件對性能的影響
將JS文件放在頁面底部將所有標簽放置在頁面的底部,緊靠body關閉標簽
的上方。這樣可以保證頁面在腳本運行之前完成解析
將JS文件打包將JS文件打包,頁面的標簽越少,頁面的加載速度越快,響應也越迅速。無論外部腳本文件還是內斂代碼都是如此
使用非阻塞方式下載在標簽中添加defer屬性
動態創建元素,用它下載并執行代碼
用XHR對象下載代碼,并注入到頁面中
數據訪問 四種訪問方式在JavaScript中,數據存儲位置可以對代碼整體性能產生重要影響,有四種數據訪問類型:直接量,變量,數組項,對象成員,這些訪問方式性能不同
直接量和局部變量訪問速度很快,而數組項和對象成員需要更長的時間
作用域鏈和閉包的訪問速度在函數內部訪問變量時,會順著作用域鏈向上查找,直到找到為止,這也意味著作用域鏈越長,平均的查找時間也就越長。而像with和try-catch會增加作用域鏈的長度,所以也會降低性能。由此可以得知,訪問全局變量很慢,因為他們在作用域鏈的最后一環
原型鏈訪問訪問對象的屬性的時候,我們有時候會需要遍歷原型鏈,這也意味著原型鏈越長,查找元素的平均效率就越低,變量所在的原型在原型鏈中越深,訪問越慢
DOM當瀏覽器下載完所有的HTML、JavaScript、CSS、圖片之后,它會解析文件并創建兩個內部數據結構:一棵DOM樹和一棵渲染樹
每個需要被顯示的DOM樹節點在渲染樹中至少有一個節點(隱藏的DOM節點自然在渲染樹中沒有節點),渲染樹上的點被稱為框或者盒,根據CSS模型定義,將頁面元素看做一個具有填充、邊距、邊框和位置的盒。一旦DOM樹和渲染樹構造完畢,瀏覽器就可以繪制頁面上的元素了。
當DOM改變影響到元素的幾何屬性(寬和高),瀏覽器就需要重新計算元素的幾何屬性。如果這個元素的改變影響到其他元素,瀏覽器會使渲染樹上收到影響的部分失效,然后重構渲染樹。這就是回流(也叫重排版)。重排版完成時,瀏覽器在一個重繪進程中重新繪制屏幕上受影響的部分
當然并不是所有DOM改變都會影響到幾何屬性,比如改變背景顏色之類的,這種情況下就只會觸發重繪
回流和重繪都是負擔很重的操作,會導致瀏覽器阻塞,所以需要盡可能避免
何時觸發回流添加或刪除可見的DOM元素
元素位置的改變
元素尺寸的改變(border、padding、margin、height、width)
內容改變
最初頁面渲染
瀏覽器窗口改變尺寸
查詢并刷新渲染樹的改變因為計算量與每次回流有關,大多數瀏覽器會通過一個渲染隊列來進行優化。但是用JavaScript獲取一些DOM屬性時,會(不由自主地)強迫隊列中的所有渲染事件前不完成。比如獲取如下屬性:
* offsetTop, offsetLeft, offsetWidth, offsetHeight
* scrollTop, scrollLeft, scrollWidth, scrollHeight
* clientTop, clientLeft, clientWidth, clientHeight
* getComputedStyle() (在IE中為currentStyle)
為了讓這些屬性返回正確的值,瀏覽器不得不運行渲染隊列中所有的渲染事件,這樣才能保證值的正確。所以盡量減少這些屬性的訪問
判斷 if-else多個if-else執行的時候,其會順序檢索每一個條件,直到所有條件檢索完或檢索到匹配的條件。所以我們可以通過樹的形式組織if語句,如下面代碼:
if(con === 1) {return result1;} else if(con === 2) {return result2;} else if(con === 3) {return result3;} else if(con === 4) {return result4;} else if(con === 5) {return result5;} else if(con === 6) {return result6;} else if(con === 7) {return result7;} else if(con === 8) {return result8;} else if(con === 9) {return result9;}
這段代碼就會依次判斷con是否等于1,2,3,4,5,6,7,8,9,如果是9的話,就會判斷9次,我們可以將其改為:
if (con <= 3){ if(con === 1) {return result1;} else if(con === 2) {return result2;} else {return result3;} } else if(con > 3 && con <= 6){ if(con === 4) {return result4;} else if(con === 5) {return result5;} else {return result6;} } else if(con <= 9){ if(con === 7) {return result7;} else if(con === 8) {return result8;} else {return result9;} }
這樣我們通過三叉樹的形式,就可以減少查找次數了,比如這里查找9次,分別判斷 0~3,3~6,6~9,7,8,9,只需要6次
if-else除了通過這種樹形組織編碼以外,還有一個優化的地方。由于其順序判斷的邏輯,我們可以根據概率來,將概率比較大的判斷放在前面,概率較小的放在后面,這樣也可以減少平均查找長度
switch事實證明,大多數情況下switch比if-else更快,但是只有條件題數量很大的時候,才能明顯更快。if-else在條件增加時,所帶來的性能負擔要高于switch,因此建議使用switch。不過switch只是用來判斷幾個不同的離散值,并沒有if-else能判斷離散值或值域那樣的靈活性
打表法可以使用打表的形式來做,把所有的處理函數放在一個數組中,然后將條件作為鍵,這種方法比switch和if-else都要快,而且在新增條件時,不會帶來額外的性能開銷
遞歸很多算法都是遞歸實現,由于遞歸會多次觸發函數調用,而函數調用也是需要開銷的(比如創建運行期上下文、壓運行期棧、創建AO、復制作用域鏈、銷毀AO、弾棧等等),所以盡量將遞歸轉變為循環。而運行期棧在很多瀏覽器中也有深度限制,當到達運行期棧的最大深度時,瀏覽器有各自的處理方式,但都是按照錯誤進行處理
字符串 不同的拼接方法字符串拼接有很多不同的方法:
1. 使用+直接拼接
2. 使用+=拼接
3. 使用Array.join()拼接
4. 使用String.concat()拼接
使用+和+=時,不同的瀏覽器會做不同程度的優化,如果在IE7和他之前的瀏覽器,優化做的不好,比如如下操作:
str += "one" + "two"
實際上會執行如下步驟:
1. 內存中創建一個臨時變量
2. 將這個臨時變量賦值成"onetow"
3. 臨時字符串與str拼接
4. 將結果賦予str
而如果改成如下這樣:
str += "one" str += "two"
這樣就可以避免創建臨時字符串,可一定程度加快性能
或者使用如下方式:
str = str + "one" + "two"
但是如果使用下面這種方式:
str = "one" + str + "two"
則無法確定是否有優化。不同的瀏覽器分配內存方式不一樣,IE以外的瀏覽器,會嘗試擴展表達式左端字符串的內存,然后簡單的將第二個字符串拷到它的尾部,這樣就會創建一個臨時字符串存放one{str原本內容},導致性能降低
瀏覽器優化很多瀏覽器會在編譯時對連續相加的字符串進行拼接,以此來對運行時優化,比如:
str += "one" + "two"
會被優化成
str += "onetwo"IE7-中的字符串連接
IE7-中使用+和+=連接很慢,而使用Array.join()方式則快得多,這也是IE7-瀏覽器中唯一高效的連接大量字符串的途徑
String.concat這種方法很慢,盡量不要使用
正則表達式優化 正則表達式的工作原理正則表達式處理經過如下幾個步驟:
1. 編譯
2. 設置起始位置
3. 匹配每個正則表達式的字元
4. 匹配成功或失敗
正則表達式實現中,回溯是基本組成部分。它代價昂貴,且容易失控。回溯是正則表達式性能的唯一因素
正則表達式在匹配時,會在一個有多個分支的地方建立標記點,然后從左到右遍歷所有的分支,如果分支符合,就會前進道下一個標記點,如果所有分支都不符合,就會回溯到上一個標記點,嘗試上一標記點的其他分支。在嘗試上一標記點的其它分支時,這一標記點如果需要,還會全部重新嘗試
回溯失控當一個正則表達式占用瀏覽器上秒,或者更長時間,很有肯那個就是回溯失控了,原因很有可能是出現了.*?這種非貪婪匹配,導致幾乎每一個字符都會被作為標記點進行嘗試
此類問題的解決辦法是盡可能具體地指出分隔符之間的字符匹配形式,或者使用前瞻表達式
嵌套量詞導致性能下降嵌套量詞可能極大的加大分支的數量,比如一個正則表達式A+A+B顯然沒有AA+B好,比如匹配AAAAAAAAAAAAAAB時,前者產生的分支要比后者多得多
一些建議關注如何讓匹配更快失敗:正則表達式慢往往不是因為成功慢,而是失敗慢,因為失敗會查找所有的情況
以簡單的,必須的字元開始:這樣可以加快失敗的匹配,如果這個開始字元都不匹配,后面的標記點就不會被匹配了
編寫兩次模板,使他們后面的資源互相排斥:當字元與鄰近的子表達式能夠重疊匹配時,路徑將顯著正價,所以需要將其具體化
減少分之數量,縮小它們的范圍:直接使用正則表達式中已有的類(如w,d)比使用|要快
使用非捕獲分組:捕獲分組花費時間和內存用于記錄后向引用,而使用后非捕獲性分組則避免這種開銷
將正則表達式分層,先捕獲感興趣的文字,然后再使用新的正則表達式處理
暴露所需的字元,盡量簡單地判斷出那些必須的字元
使用適當的量詞,貪婪量詞和懶惰量詞在匹配同樣字符串時過程是不同的,在確保正確的前提下,選擇回溯次數更少的量詞可以提高性能
將正則表達式賦給變量,以重用他們。正則表達式創建時,需要對他們進行編譯,這個編譯也會有額外的開銷
將復雜的正則表達式拆分成簡單的片段,避免使用一個表達式做太多的工作,可以通過兩個或多個正則表達式來解決
UI線程相關建議的一次JavaScript執行時間不超過100ms(最好在50ms)以內,可以通過setTimeout和setInterval來將任務進行分解,加入到UI線程中。其實這個思想和JavaScript引擎的垃圾回收器的迭代處理相似
AJAXAJAX獲取數據時,可以使用POST或者GET方法
如果請求不改變服務器狀態指示返回數據,應該使用GET。GET請求會被緩存,如果多次提取相同的數據會提高性能
而當URL和請求的參數長度超過2048個字符的時候才使用POST提取數據
多部分XHR(MXHR)多部分XHR允許使用一個HTTP請求獲取多個資源,我們可以將資源打包成一個特定分隔符定界的大字符串,從服務器發送到客戶端,JavaScript處理這些大字符串,然后根據它自身的類型和信息解析出每個資源
需要注意的是AJAX不會在瀏覽器中進行緩存,自然使用MXHR也不會緩存,在一些靜態資源上使用這種方式其實并不太好。但是如果每次都確實需要去獲取,分多個請求發送會更慢。
IMG燈標我們可以通過創建一個Image對象,將src設為一個腳本文件的URL,img元素我們并不需要插入到DOM中,這種形式稱為IMG燈標
這種方式適用于GET請求,且服務器獲得數據后不必返回數據給瀏覽器的情況
同時我們可以在Image的load事件中監聽服務端是否成功接受了數據
數據格式XML:支持廣泛但解析效率低,而且相當冗長
JSON: 小巧,輕便,解析速度較快
JSONP:使用JavaScript解釋器進行解析,解析速度極快,數據量只比JSON多一點點(函數名稱和括號)
HTML:無需解析,數據冗長
自定義格式:自己解析,慢而易出錯,數據長度可以很短
其他不要使用eval以及其類似
使用字面量
避免重復工作,檢測瀏覽器時,保存首次檢測結果即可
考慮位操作
使用原聲方法,因為他們是C++寫的
文件預處理,壓縮(gzip)、合并、uglify
嘗試CDN
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/78068.html
摘要:而像和會增加作用域鏈的長度,所以也會降低性能。但是用獲取一些屬性時,會不由自主地強迫隊列中的所有渲染事件前不完成。在條件增加時,所帶來的性能負擔要高于,因此建議使用。它代價昂貴,且容易失控。 正巧看到在送書,于是乎找了找自己博客上記錄過的一些東西來及其無恥的蹭書了~~~ 小廣告:更多內容可以看我的博客 以下內容均來自《高性能JavaScript》 JavaScript文件加載 ...
摘要:特意對前端學習資源做一個匯總,方便自己學習查閱參考,和好友們共同進步。 特意對前端學習資源做一個匯總,方便自己學習查閱參考,和好友們共同進步。 本以為自己收藏的站點多,可以很快搞定,沒想到一入匯總深似海。還有很多不足&遺漏的地方,歡迎補充。有錯誤的地方,還請斧正... 托管: welcome to git,歡迎交流,感謝star 有好友反應和斧正,會及時更新,平時業務工作時也會不定期更...
閱讀 1963·2021-10-25 09:48
閱讀 2782·2021-09-22 14:59
閱讀 1755·2019-08-29 16:52
閱讀 854·2019-08-29 16:07
閱讀 2298·2019-08-29 12:38
閱讀 1751·2019-08-26 13:23
閱讀 875·2019-08-26 11:49
閱讀 3264·2019-08-26 10:56