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