摘要:所以會導致一些性能上的問題當異常被捕獲的時候。注意對象的轉換字面量,比如字符串,數字或者布爾值,在中有兩種表現,它門可能被當作單純的值或者一個對象。使用字符串的累加形式。
原文鏈接:https://dev.opera.com/articles/efficient-javascript/?page=2#primitiveo...
高效的JavaScript曾經,一個Web頁面不會包含太多的腳本,或者至少來說,它們不會影響頁面的性能。然而,現在的Web頁面越來越像本地運用了,腳本的性能成了一個很大的影響隨著越來越多的運用轉向使用Web技術時,提高頁面的性能成為了越來越重要的問題。
ECMAScript 避免使用eval和Function構造函數每次當eval和Function constructor通過字符串源碼形式調用時,腳本引擎必須開啟轉換機制將字符串源碼轉換成可執行的代碼。通常來說這是比較耗性能的。
eval調用特別的不好,當執行的內容字符串傳遞給eval時不能被提前執行,由于代碼執行會被eval中執行的內容影響,那就意味著編譯器不能更好的優化執行上下文,并且瀏覽器在運行時時放棄執行下面的上下文。這樣就增加了額外的性能影響。
對于Function constructor來說,它的名聲和eval一樣也不太好,雖然使用它并不會影響上下文的執行,但是它執行的效率卻很低下。示例代碼如下:
錯誤的使用eval:
function getProperty(oString) { var oReference; eval("oReference = test.prop." + oString); return oReference; }
正確的姿勢:
function getProperty(oString) { return test.prop[oString]; }
錯誤的使用Function constructor:
function addMethod(oObject, oProperty, oFunctionCode) { oObject[oProperty] = new Function(oFunctionCode); } addMethod( myObject, "rotateBy90", "this.angle = (this.angle + 90) % 360" ); addMethod( myObject, "rotateBy60", "this.angle = (this.angle + 60) % 360" );
正確的姿勢:
function addMethod(oObject, oProperty, oFunction) { oObject[oProperty] = oFunction; } addMethod( myObject, "rotateBy90", function() { this.angle = (this.angle + 90) % 360; } ); addMethod( myObject, "rotateBy60", function() { this.angle = (this.angle + 60) % 360; } );避免使用with
盡管對于開發人員來說,使用with比較方便,但是對性能來說,卻是非常消耗的。原因是對腳本引擎來說,它會拓展作用域鏈,而查找變量的時候不會判斷是否被當前引用。盡管這種情況帶來性能的開銷比較少,但是每次編譯的時候我們都不知道內容的作用域,那就意味著編譯器不能對其進行優化,所以它就和普通的作用域一樣。
一種更有效的方法代替方法是使用一個對象變量來代替with的使用。屬性的訪問可以通過對象的引用來實現。這樣工作起來非常有效,如果屬性不是基本類型外,比如字符串和布爾值。
考慮下面的代碼:
with(test.information.settings.files) { primary = "names"; secondary = "roles"; tertiary = "references"; }
使用下面的方式效率更高:
var testObject = test.information.settings.files; testObject.primary = "names"; testObject.secondary = "roles"; testObject.tertiary = "references";不要在循環的函數里面使用try-catch-finally
try-catch-finally語句相對于其他的語句來說它的結構非常唯一的,當腳本運行的時候它會在當前的作用域總創建一個變量,這發生在catch語句調用的時候.捕獲的異常對象會關聯這個變量,這個變量不會存在其他的腳本里,即使是相同的作用域。它在catch語句開始的時候創建,在執行結束的時候銷毀它。
因為這個變量會在運行的時候創建和銷毀,所以會產生一種特殊的情況,一些瀏覽器不能及時的在性能比較耗的循環中及時捕獲該句柄。所以會導致一些性能上的問題當異常被捕獲的時候。
如果可能的話,異常的執行應該在更高的級別執行,這樣它就不會頻繁的出現,或者通過檢查期望的動作最早被允許的話來避免,下面通過示例來說明:
錯誤的使用方式:
var oProperties = [ "first", "second", "third", … "nth" ]; for(var i = 0; i < oProperties.length; i++) { try { test[oProperties[i]].someproperty = somevalue; } catch(e) { … } }
在許多情況下,try-catch-finally結構可以移動到循環的外圍, 這樣看起來似乎語意上有點改變。由于異常拋出時,循環會被中斷,但是下面的代碼會依然執行。
var oProperties = [ "first", "second", "third", … "nth" ]; try { for(var i = 0; i < oProperties.length; i++) { test[oProperties[i]].someproperty = somevalue; } } catch(e) { … }
在某些情況下,try-catch-finally結構可以避免使用。比如:
var oProperties = [ "first", "second", "third", … "nth" ]; for(var i = 0; i < oProperties.length; i++) { if(test[oProperties[i]]) { test[oProperties[i]].someproperty = somevalue; } }隔離eval和with的使用
由于這些結構影響性能如此的深,所以它們使用的越少越好。但是有時候你可能需要它們,如果一個函數被調用或者一個循環重復的被計算,最好的方式還是避免使用這些結構,他們最好的解決方案就是被執行一次,或者極少數,以至于基本上對性能沒什么影響。
避免使用全局變量在全局范圍內創建一個變量是很誘惑的,只因它創建的方式很簡單,但是有一下幾個原因會導致腳本運行變慢。
首先,全局變量需要腳本引擎查找到最外的作用域,查找速度比較慢,第二,全局變量通過window對象被分享,意味著本質上它有兩層作用域(??)。
注意對象的轉換字面量,比如字符串,數字或者布爾值,在ECMAScript中有兩種表現,它門可能被當作單純的值或者一個對象。
任何屬性或者方法被調用的時候針對的是這個對象,不是這個值,當你引用一個屬性或者方法的時候,ECMAScript引擎會暗中的創建一個你值對應的字符串對象。在方法調用之前。這個對象只會被請求一次,當你嘗試下一次調用該值的某個方法時它又會被創建一次。來看看下面的例子:
var s = "0123456789"; for(var i = 0; i < s.length; i++) { s.charAt(i); }
上面的例子需要腳本引擎創建21次字符串對象,一次length屬性的訪問,一次charAt方法的調用。
優化的方案如下所示:
var s = new String("0123456789"); for(var i = 0; i < s.length; i++) { s.charAt(i); }
和上面等效,但是僅僅手動創建了一個對象,性能上要比上面的好很多。
注意:不同的瀏覽器,對于裝箱和拆箱的優化不一樣。
避免咋性能堪憂的函數里使用for-in迭代for-in迭代有它自己的特點,但是它經常被濫用,這種迭代需要腳本引擎創建一個所有可枚舉屬性的清單,并檢出為當作副本,在開始枚舉的時候。
使用字符串的累加形式。字符串的拼接是個昂貴的過程,當使用"+"運算符時,它不會把結果立即添加到變量中,反而它會創建一個新的字符串對象在內存中,并把得到的結果賦值個這個字符串。然后這個新的字符串對象在賦值給變量。但是使用"+="可以避免這樣的過程。
原始的操作符可能比函數調用更快示例:
var min = Math.min(a,b); A.push(v);
下面的方式和上面的等效,但是效率更高:
var min = a < b ? a : b; A[A.length] = v;傳遞一個回調函數而不是字符串給setTimeout()和setInterval()
當setTimeout()和setInterval()方法傳遞的是個字符串時,它內部會調用eval,所以會導致性能上的問題。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/85631.html
摘要:前端日報精選的作用鳥瞰前端再論性能優化翻譯給創始人和們的許可協議解惑如何工作引擎深入探究優化代碼的個技巧譯文第期還是,讓我來解決你的困惑中文基礎為什么比快二分查找法你真的寫對了嗎個人文章推薦機不可失直播技術盛宴,深圳騰訊開發者大 2017-09-21 前端日報 精選 setTimeout(fn, 0) 的作用鳥瞰前端 , 再論性能優化翻譯:給創始人和 CTO 們的 React 許可協議...
摘要:至于,其只是以數組的方傳入參數,其它部分是一樣的,如下它們也可用于在中的類繼承中,調用父級構造器。間接調用,調用了父級構造器對比方法和,它倆都立即執行了函數,而函數返回了一個新方法,綁定了預先指定好的,并可以延后調用。 其實this是一個老生常談的問題了。關于this的文章非常多,其實我本以為自己早弄明白了它,不過昨天在做項目的過程中,還是出現了一絲疑惑,想到大概之前在JavaScri...
摘要:所以我說的這些類數組對象是什么它們有一些,其中包括是一個很特殊的變量,你再所有函數體內都可以訪問到。讓類數組對象成為一個數組當然這個標題是不太準確的,假如我們需要將這些類數組對象變成數組一樣,我們需要建立一個新的數組。 它看起來像是一個數組,而且它有一個length屬性,然而它并不是一個數組。JavaScript有時候是一門很怪異的語言,因為你很難定義一個數組的概念而沒有什么例外的。所...
摘要:事件循環了解了在引擎中是如何工作了之后,來看下如何使用異步回調函數來避免代碼。從回調函數被放入后秒鐘,把移到中。由于事件循環持續地監測調用棧是否已空,此時它一注意到調用棧空了,就調用并創建一個新的調用棧。 聽多了JavaScript單線程,異步,V8,便會很想去知道JavaScript是如何利用單線程來實現所謂的異步的。我參考了一些文章,了解到一個很重要的詞匯:事件循環(Event L...
摘要:也許最好的理解是閉包總是在進入某個函數的時候被創建,而局部變量是被加入到這個閉包中。在函數內部的函數的內部聲明函數是可以的可以獲得不止一個層級的閉包。 前言 總括 :這篇文章使用有效的javascript代碼向程序員們解釋了閉包,大牛和功能型程序員請自行忽略。 譯者 :文章寫在2006年,可直到翻譯的21小時之前作者還在完善這篇文章,在Stackoverflow的How do Java...
閱讀 2770·2021-11-23 09:51
閱讀 3529·2021-10-08 10:17
閱讀 1262·2021-10-08 10:05
閱讀 1310·2021-09-28 09:36
閱讀 1833·2021-09-13 10:30
閱讀 2174·2021-08-17 10:12
閱讀 1670·2019-08-30 15:54
閱讀 2004·2019-08-30 15:53