小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

JS優(yōu)化

 suweixin 2011-01-15
JS優(yōu)化 收藏
< type="text/javascript"> JS優(yōu)化已經(jīng)討論了很多了,最近又看到aimingoo的一篇。大體上,aimingoo的說(shuō)法都是非常正確的。
除了像aimingoo做個(gè)案研究外,這里我想從更一般的角度總結(jié)在瀏覽器編程中JS優(yōu)化的幾個(gè)原則。
首先,與其他語(yǔ)言不同,JS的效率很大程度是取決于JS engine的效率。除了引擎實(shí)現(xiàn)的優(yōu)劣外,引擎自己也會(huì)為一些特殊的代碼模式采取一些優(yōu)化的策略。例如FF、Opera和Safari的JS引擎,都對(duì)字符串的拼接運(yùn)算(+)做了特別優(yōu)化。顯然,要獲得最大效率,就必須要了解引擎的脾氣,盡量迎合引擎的口味。所以對(duì)于不同的引擎,所作的優(yōu)化極有可能是背道而馳的。
而如果做跨瀏覽器的web編程,則最大的問(wèn)題是在于IE6(JScript 5.6)!因?yàn)樵诓淮騢otfix的情況下,JScript引擎的垃圾回收的bug,會(huì)導(dǎo)致其在真實(shí)應(yīng)用中的performance跟其他瀏覽器根本不在一個(gè)數(shù)量級(jí)上。因此在這種場(chǎng)合做優(yōu)化,實(shí)際上就是為JScript做優(yōu)化!
所以第一原則就是只需要為IE6(未打補(bǔ)丁的JScript 5.6或更早版本)做優(yōu)化!
如果你的程序已經(jīng)優(yōu)化到在IE6下可以接受的性能,那基本上在其他瀏覽器上性能就完全沒(méi)有問(wèn)題。
因此,注意我下面講的許多問(wèn)題在其他引擎上可能完全不同,例如在循環(huán)中進(jìn)行字符串拼接,通常認(rèn)為需要用Array.join的方式,但是由于SpiderMonkey等引擎對(duì)字符串的“+”運(yùn)算做了優(yōu)化,結(jié)果使用Array.join的效率反而不如直接用“+”!但是如果考慮IE6,則其他瀏覽器上的這種效率的差別根本不值一提。
JS優(yōu)化與其他語(yǔ)言的優(yōu)化也仍然有相同之處。比如說(shuō),不要一上來(lái)就急吼吼的做優(yōu)化,那樣毫無(wú)意義。優(yōu)化的關(guān)鍵,仍然是要把精力放在最關(guān)鍵的地方,也就是瓶頸上。一般來(lái)說(shuō),瓶頸總是出現(xiàn)在大規(guī)模循環(huán)的地方。這倒不是說(shuō)循環(huán)本身有性能問(wèn)題,而是循環(huán)會(huì)迅速放大可能存在的性能問(wèn)題。
所以第二原則就是以大規(guī)模循環(huán)體為最主要優(yōu)化對(duì)象。
以下的優(yōu)化原則,只在大規(guī)模循環(huán)中才有意義,在循環(huán)體之外做此類優(yōu)化基本上是沒(méi)有意義的。
目前絕大多數(shù)JS引擎都是解釋執(zhí)行的,而解釋執(zhí)行的情況下,在所有操作中,函數(shù)調(diào)用的效率是較低的。此外,過(guò)深的prototype繼承鏈或者多級(jí)引用也會(huì)降低效率。JScript中,10級(jí)引用的開(kāi)銷大體是一次空函數(shù)調(diào)用開(kāi)銷的1/2。這兩者的開(kāi)銷都遠(yuǎn)遠(yuǎn)大于簡(jiǎn)單操作(如四則運(yùn)算)。
所以第三原則就是盡量避免過(guò)多的引用層級(jí)和不必要的多次方法調(diào)用。
特別要注意的是,有些情況下看似是屬性訪問(wèn),實(shí)際上是方法調(diào)用。例如所有DOM的屬性,實(shí)際上都是方法。在遍歷一個(gè)NodeList的時(shí)候,循環(huán)條件對(duì)于nodes.length的訪問(wèn),看似屬性讀取,實(shí)際上是等價(jià)于函數(shù)調(diào)用的。而且IE DOM的實(shí)現(xiàn)上,childNodes.length每次是要通過(guò)內(nèi)部遍歷重新計(jì)數(shù)的。(My god,但是這是真的!因?yàn)槲覝y(cè)過(guò),childNodes.length的訪問(wèn)時(shí)間與childNodes.length的值成正比?。┻@非常耗費(fèi)。所以預(yù)先把nodes.length保存到j(luò)s變量,當(dāng)然可以提高遍歷的性能。
同樣是函數(shù)調(diào)用,用戶自定義函數(shù)的效率又遠(yuǎn)遠(yuǎn)低于語(yǔ)言內(nèi)建函數(shù),因?yàn)楹笳呤菍?duì)引擎本地方法的包裝,而引擎通常是c,c++,java寫(xiě)的。進(jìn)一步,同樣的功能,語(yǔ)言內(nèi)建構(gòu)造的開(kāi)銷通常又比內(nèi)建函數(shù)調(diào)用要效率高,因?yàn)榍罢咴贘S代碼的parse階段就可以確定和優(yōu)化。
所以第四原則就是盡量使用語(yǔ)言本身的構(gòu)造和內(nèi)建函數(shù)。
這里有一個(gè)例子是高性能的String.format方法。String.format傳統(tǒng)的實(shí)現(xiàn)方式是用String.replace(regex, func),在pattern包含n個(gè)占位符(包括重復(fù)的)時(shí),自定義函數(shù)func就被調(diào)用n次。而這個(gè)高性能實(shí)現(xiàn)中,每次format調(diào)用所作的只是一次Array.join然后一次String.replace(regex, string)的操作,兩者都是引擎內(nèi)建方法,而不會(huì)有任何自定義函數(shù)調(diào)用。兩次內(nèi)建方法調(diào)用和n次的自定義方法調(diào)用,這就是性能上的差別。
同樣是內(nèi)建特性,性能上也還是有差別的。例如在JScript中對(duì)于arguments的訪問(wèn)性能就很差,幾乎趕上一次函數(shù)調(diào)用了。因此如果一個(gè)可變參數(shù)的簡(jiǎn)單函數(shù)成為性能瓶頸的時(shí)候,可以將其內(nèi)部做一些改變,不要訪問(wèn)arguments,而是通過(guò)對(duì)參數(shù)的顯式判斷來(lái)處理。
比如:
Java代碼
function sum() {   
    var r = 0;   
    for (var i = 0; i < arguments.length; i++) {   
        r += arguments[i];   
    }   
    return r;   
}  
 function sum() {
  var r = 0;
  for (var i = 0; i < arguments.length; i++) {
   r += arguments[i];
  }
  return r;
 }
這個(gè)sum通常調(diào)用的時(shí)候個(gè)數(shù)是較少的,我們希望改進(jìn)它在參數(shù)較少時(shí)的性能。如果改成:
Java代碼
function sum() {   
    switch (arguments.length) {   
        case 1: return arguments[0];   
        case 2: return arguments[0] + arguments[1];   
        case 3: return arguments[0] + arguments[1] + arguments[2];   
        case 4: return arguments[0] + arguments[1] + arguments[2] + arguments[3];   
        default:   
            var r = 0;   
            for (var i = 0; i < arguments.length; i++) {   
                r += arguments[i];   
            }   
            return r;   
    }   
}  
 function sum() {
  switch (arguments.length) {
   case 1: return arguments[0];
   case 2: return arguments[0] + arguments[1];
   case 3: return arguments[0] + arguments[1] + arguments[2];
   case 4: return arguments[0] + arguments[1] + arguments[2] + arguments[3];
   default:
    var r = 0;
    for (var i = 0; i < arguments.length; i++) {
     r += arguments[i];
    }
    return r;
  }
 }
其實(shí)并不會(huì)有多少提高,但是如果改成:
Java代碼
function sum(a, b, c, d, e, f, g) {   
    var r = a ? b ? c ? d ? e ? f ? a + b + c + d + e + f : a + b + c + d + e : a + b + c + d : a + b + c : a + b : a : 0;   
    if (g === undefined) return r;   
    for (var i = 6; i < arguments.length; i++) {   
        r += arguments[i];   
    }   
    return r;   
}  
 function sum(a, b, c, d, e, f, g) {
  var r = a ? b ? c ? d ? e ? f ? a + b + c + d + e + f : a + b + c + d + e : a + b + c + d : a + b + c : a + b : a : 0;
  if (g === undefined) return r;
  for (var i = 6; i < arguments.length; i++) {
   r += arguments[i];
  }
  return r;
 }
就會(huì)提高很多(至少快1倍)。
最后是第五原則,也往往是真實(shí)應(yīng)用中最重要的性能障礙,那就是盡量減少不必要的對(duì)象創(chuàng)建。
本身創(chuàng)建對(duì)象是有一定的代價(jià)的,但是這個(gè)代價(jià)其實(shí)并不大。最根本的問(wèn)題是由于JScript愚蠢之極的垃圾回收調(diào)度算法,導(dǎo)致隨著對(duì)象個(gè)數(shù)的增加,性能嚴(yán)重下降(據(jù)微軟的人自己說(shuō)復(fù)雜度是O(n^2))。
比如我們常見(jiàn)的字符串拼接問(wèn)題,經(jīng)過(guò)我的測(cè)試驗(yàn)證,單純的多次創(chuàng)建字符串對(duì)象其實(shí)根本不是性能差的原因。要命的是在對(duì)象創(chuàng)建期間的無(wú)謂的垃圾回收的開(kāi)銷。而Array.join的方式,不會(huì)創(chuàng)建中間字符串對(duì)象,因此就減少了那該死的垃圾回收的開(kāi)銷。
因此,如果我們能把大規(guī)模對(duì)象創(chuàng)建轉(zhuǎn)化為單一語(yǔ)句,則其性能會(huì)得到極大的提高!例如通過(guò)構(gòu)造代碼然后eval——實(shí)際上PIES項(xiàng)目中正在根據(jù)這個(gè)想法來(lái)做一個(gè)專門(mén)的大規(guī)模對(duì)象產(chǎn)生器……
關(guān)于DOM遍歷的補(bǔ)充:
如前所述,IE6 DOM中childNodes.length每次都是要遍歷所有節(jié)點(diǎn)統(tǒng)計(jì)個(gè)數(shù)得出的。而childNodes[i]的訪問(wèn),也要遍歷直到第i個(gè)元素。所以在子節(jié)點(diǎn)數(shù)量巨大的情況下(超過(guò)1000),不宜使用for循環(huán)來(lái)遍歷childNodes,否則會(huì)死得很慘。而應(yīng)使用這樣的遍歷方法:
Java代碼
var node = elem.firstChild;   
while (node != null) {   
    ...   
    node = node.nextSibling;   
}  
var node = elem.firstChild;
while (node != null) {
 ...
 node = node.nextSibling;
}

另一個(gè)方式是使用IE自己的DHTML集合屬性elem.children,但是它與childNodes不同,不包含文本節(jié)點(diǎn)。
 
本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/allanking666/archive/2009/06/02/4236383.aspx

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多