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