国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

高性能JavaScript閱讀簡(jiǎn)記(三)

leiyi / 2672人閱讀

摘要:移植到中的一個(gè)典型的達(dá)夫設(shè)備的例子為一個(gè)很長(zhǎng)很長(zhǎng)的數(shù)組。但是達(dá)夫設(shè)備最初這種詭異的寫(xiě)法和思路,還是驚艷了很多人的,值得我們思考。高性能閱讀簡(jiǎn)記一高性能閱讀簡(jiǎn)記二高性能閱讀簡(jiǎn)記三

四、Aligorithms and Flow Control 算法和流程控制 1、Loops 循環(huán)

a、避免使用for/in循環(huán)
在JavaScript標(biāo)準(zhǔn)中,有四種類型循環(huán)。for、for/in、while、do/while,其中唯一一個(gè)性能比其他明顯慢的是for/in。對(duì)于for/in循環(huán)的使用場(chǎng)景,更多的是針對(duì)不確定內(nèi)部結(jié)構(gòu)的對(duì)象的循環(huán)。for/in會(huì)枚舉對(duì)象的命名屬性,只有完全遍歷對(duì)象的所有屬性之后包括實(shí)例屬性和從原型鏈繼承的屬性,循環(huán)才會(huì)返回。正因?yàn)?b>for/in循環(huán)需要搜索實(shí)例或者原型的屬性,所以for/in的性能要差很多,因此我們需要盡量避免使用for/in循環(huán),對(duì)于那些已知屬性列表的對(duì)象,更需要避免使用for/in。

b、Decreasing the work per iteration 減少迭代的工作量
一個(gè)標(biāo)準(zhǔn)的for循環(huán)組成:

(初始化體; 前側(cè)條件/控制條件; 后執(zhí)行體){
    循環(huán)體;
}

可能對(duì)于單次循環(huán)操作,我們所做的性能優(yōu)化看起來(lái)沒(méi)什么用,但是對(duì)于多次循環(huán),這些性能優(yōu)化加起來(lái)是很明顯的。

for (var i = 0; i < items.length; i++){
    eventHandler(items[i]);
}

對(duì)于上面這樣一個(gè)經(jīng)典的for循環(huán),它的單次操作中,需要做這些工作:

①在控制條件中讀一次屬性(items.length)
②在控制條件中進(jìn)行一次比較(i < items.length)
③比較操作,判斷條件控制體的結(jié)果是否為true(i < items.length == true)
④一次自加操作(i++)
⑤一次數(shù)組查找(items[i])
⑥一次函數(shù)調(diào)用(eventHandler(items[i]);)

大家都知道的一個(gè)優(yōu)化就是在第一步,每一次的循環(huán)中都會(huì)查詢一次items.length,這個(gè)操作會(huì)首先查找items,然后計(jì)算長(zhǎng)度,一方面,查找items時(shí)的性能開(kāi)銷(xiāo)是浪費(fèi)的,另一方面,訪問(wèn)一個(gè)局部變量或者是字面量,顯然更快。因此在這里,我們可以通過(guò)一個(gè)變量緩存items.length,對(duì)于較長(zhǎng)的數(shù)組,可以節(jié)約25%的總循環(huán)時(shí)間(ie中可達(dá)到50%)。
另一種提升循環(huán)體性能的方法是改變循環(huán)的順序,這常用于數(shù)組元素的處理順序和任務(wù)無(wú)關(guān)的情況,從最后一個(gè)元素開(kāi)始,直到處理完第一個(gè)元素。

for(var i = items.length; i--){
    eventHandler(items[i]);
}

在一個(gè)for循環(huán)中,可以省略初始化體和后執(zhí)行體,這里省略了后執(zhí)行體,也就是當(dāng)i -- 之后, i!= flase,則執(zhí)行eventHandler(items[i]);這里的ii--之后的值。這里優(yōu)化地方是將我們前面說(shuō)的2、3優(yōu)化了成一步,i是否是true;如果是則執(zhí)行i--,也就是i = i - 1;
進(jìn)行這兩方面的優(yōu)化后,循環(huán)體的性能會(huì)得到顯著提升。

c、Decreasing the number of iterations 減少迭代次數(shù)
除了在設(shè)計(jì)循環(huán)之前周密考慮,使用最優(yōu)的循環(huán)模式,減少迭代次數(shù),另一個(gè)減少迭代次數(shù)的有名的方法是達(dá)夫設(shè)備Duff"s Device),達(dá)夫設(shè)備最早出現(xiàn)于C中,他的設(shè)計(jì)理念,是將整個(gè)循環(huán)每8個(gè)一份分成o份并取余數(shù)p,第一次循環(huán)執(zhí)行n次循環(huán)體,然后執(zhí)行m次循環(huán),每次循環(huán)中執(zhí)行8次循環(huán)體中的操作,這樣原本是m * 8 + n 次循環(huán)就變成了m + 1次循環(huán)。這對(duì)于那些循環(huán)體耗時(shí)很短的循環(huán)來(lái)講,降低了在判斷條件上浪費(fèi)的時(shí)間,從而提升性能。移植到j(luò)avascript中的一個(gè)典型的達(dá)夫設(shè)備的例子:

var m = [1,2,3,...];        //為一個(gè)很長(zhǎng)很長(zhǎng)的數(shù)組。
var o = Math.floor(m.length/8);
var p = m.length % 8 ;
var i = 0;
do{
switch(p){
    case 0 : console.log(m[i++]);
    case 7 : console.log(m[i++]);
    case 6 : console.log(m[i++]);
    case 5 : console.log(m[i++]);
    case 4 : console.log(m[i++]);
    case 3 : console.log(m[i++]);
    case 2 : console.log(m[i++]);
    case 1 : console.log(m[i++]);
}
p = 0;
}while(--o);

書(shū)上的達(dá)夫設(shè)備的代碼如上,但是在我看來(lái)這段代碼是有問(wèn)題的,除非m也就是初始循環(huán)次數(shù)是8的整倍數(shù),否則循環(huán)會(huì)少執(zhí)行一輪,也就是8次。不過(guò)沒(méi)有找到這本書(shū)的勘誤,自行完善了一下這里的代碼:

var m = [1,2,3,...];
var o = Math.floor(m.length/8);
var p = m.length % 8 ;
p === 0 ? "" : o++;
var i = 0;
do{
switch(p){
    case 0 : console.log(m[i++]);
    case 7 : console.log(m[i++]);
    case 6 : console.log(m[i++]);
    case 5 : console.log(m[i++]);
    case 4 : console.log(m[i++]);
    case 3 : console.log(m[i++]);
    case 2 : console.log(m[i++]);
    case 1 : console.log(m[i++]);
}
p = 0;
}while(--o);

理解上面的代碼需要首先明確一點(diǎn),不管是在C中還是JavaScript中,如果switch語(yǔ)句中沒(méi)有break,則會(huì)在匹配到第一個(gè)case并執(zhí)行后執(zhí)行下一個(gè)case中的操作,不管下一個(gè)case是否匹配,直到遇到break或者結(jié)束的大括號(hào),當(dāng)然,return也可以。
上面switch版本的達(dá)夫設(shè)備的改進(jìn)版是去掉了switch而變得更快,書(shū)中的代碼是個(gè)死循環(huán)(難道因?yàn)槲铱吹氖莗df版本的有誤,原書(shū)是對(duì)的嗎),就不貼出來(lái)禍害人了,我這梳理后重寫(xiě)的代碼如下:

var m = [1,2,3,...];
var p = m.length % 8 ;
while(p){
    console.log(m[--p]);
}
var i = m.length;
var o = Math.floor(m.length/8);
while(o--){
    console.log(m[--i]);
    console.log(m[--i]);
    console.log(m[--i]);
    console.log(m[--i]);
    console.log(m[--i]);
    console.log(m[--i]);
    console.log(m[--i]);
    console.log(m[--i]);
}

這個(gè)版本中的達(dá)夫設(shè)備將主循環(huán)和余數(shù)處理的部分分開(kāi),并將原數(shù)組進(jìn)行倒序處理。代碼很易懂就不多說(shuō)。
在實(shí)測(cè)中,達(dá)夫設(shè)備的性能并不比傳統(tǒng)的for循環(huán)快多少,甚至普遍會(huì)慢那么一點(diǎn)點(diǎn)(FireFox不管處理什么樣的循環(huán),都比Chrome慢三倍,這個(gè)必須吐槽一下),這是因?yàn)樵诂F(xiàn)代瀏覽器中,隨著設(shè)備性能的提升,瀏覽器的實(shí)現(xiàn)對(duì)循環(huán)的算法優(yōu)化的越來(lái)越好,在瀏覽器內(nèi)部處理循環(huán)時(shí)也會(huì)采用自己獨(dú)特的算法提升循環(huán)的性能,編程時(shí)達(dá)夫設(shè)備帶來(lái)的性能提升已經(jīng)慢慢的變得不足為道;加上達(dá)夫設(shè)備這種寫(xiě)法,對(duì)于代碼可讀性很不友好,因此現(xiàn)在已經(jīng)慢慢越來(lái)越少會(huì)有人采用這樣的方式來(lái)做性能優(yōu)化。但是達(dá)夫設(shè)備最初這種詭異的寫(xiě)法和思路,還是驚艷了很多人的,值得我們思考。

2、Function-Based Iteration 基于函數(shù)的迭代

在多數(shù)現(xiàn)代瀏覽器的實(shí)現(xiàn)中,forEach可作為一個(gè)原生的方法去使用,此方法相當(dāng)于遍歷數(shù)組的所有成員,并在每個(gè)成員上執(zhí)行一個(gè)函數(shù),每個(gè)成員上執(zhí)行的函數(shù)作為forEach()的參數(shù)傳進(jìn)去。這種情況下,每一個(gè)數(shù)組成員都被掛載了一個(gè)函數(shù),在執(zhí)行迭代時(shí)調(diào)用,這種基于函數(shù)的迭代比基于循環(huán)的迭代要慢很多,在實(shí)測(cè)中,會(huì)慢20%左右。復(fù)雜的函數(shù)處理的時(shí)候,性能上的問(wèn)題會(huì)更突出。

3、Conditionals 條件表達(dá)式

a、if-else Versus switch if-else與switch比較
大家約定俗稱的一點(diǎn)是,在條件數(shù)量較少時(shí)傾向于使用if-else,在條件數(shù)量較大時(shí)使用switch,不管從代碼可讀性考慮,還是從性能方面考慮,這種做法都是正確的。盡管在實(shí)際上,較少條件數(shù)量時(shí),使用switch多數(shù)情況下也比if-else快,但也只是快的微不足道,因此這種約定俗稱的使用方式是沒(méi)有問(wèn)題的。

b、Optimzing if-else 優(yōu)化if-else
if-else決定了JavaScript運(yùn)行流的走向,讓JavaScript運(yùn)行流盡快找到運(yùn)行條件并運(yùn)行顯然會(huì)提高函數(shù)的執(zhí)行效率,因此在有多個(gè)條件數(shù)量時(shí),讓最可能出現(xiàn)的條件排在前面。例如,用js設(shè)置中獎(jiǎng)概率,一等獎(jiǎng)概率10%,二等獎(jiǎng)概率20%;三等獎(jiǎng)概率30%;不中獎(jiǎng)概率40%;更多人的習(xí)慣寫(xiě)法是:

var result = Math.random() * 10;
if(result <= 1){
    //一等獎(jiǎng)
}else if(result > 1 && result <= 3){
    //二等獎(jiǎng)
}else if(result > 3 && result <= 6){
    //三等獎(jiǎng)
}else{
    //不中獎(jiǎng)
}

實(shí)際上,最可能出現(xiàn)的是不中獎(jiǎng),但是每次在判斷為不中獎(jiǎng)之前需要先進(jìn)行前三次判斷,此時(shí)可以做的優(yōu)化就是將上述的寫(xiě)法反過(guò)來(lái):

var result = Math.random() * 10;
if(result <= 4){
    //不中獎(jiǎng)
}else if(result > 4 && result <= 7){
    //三等獎(jiǎng)
}else if(result > 7 && result <= 9){
    //二等獎(jiǎng)
}else{
    //一等獎(jiǎng)
}

當(dāng)然,較真性能的話,這里用switch更好,不過(guò)我們考慮的是優(yōu)化if-else的性能。
另外一種減少條件判斷的長(zhǎng)度的辦法是將并列的if-else判斷,組織成嵌套的if-else減少平均的條件判斷長(zhǎng)度,例如下面的例子:

var result = Math.floor(Math.random() * 10);
if(result === 0){
    return 0;
}else if(result === 1){
    return 1;
}else if(result === 2){
    return 2;
}else if(result === 3){
    return 3;
}else if(result === 4){
    return 4;
}else if(result === 5){
    return 5;
}else if(result === 6){
    return 6;
}else if(result === 7){
    return 7;
}else if(result === 8){
    return 8;
}else if(result === 9){
    return 9;
}

這時(shí)候計(jì)算條件體的最大數(shù)目是9,我們可以通過(guò)嵌套判斷的辦法減少計(jì)算判斷體的數(shù)目:

if(result < 6){
    if(result < 3){
        if(result === 0){
            return 0;
        }else if(result === 1){
            return 1;
        }else{
            return 2;
        }
    }else{
        if(result === 3){
            return 3;
        }else if(result === 4){
            return 4;
        }else{
            return 5;
        }
    }
}else{
    if(result < 8){
        if(result === 6){
            return 6;
        }else{
            return 7;
        }
    }else{
        if(result === 8){
            return 8;
        }else{
            return 9;
        }
    }
}

看起來(lái)代碼是多了,但是最大的條件判斷數(shù)變成了4,一定程度上提升了性能。當(dāng)然,這種情況下,一般會(huì)使用swtich處理的。

c、Lookup Tables 查表法
當(dāng)有大量的離散值需要測(cè)試時(shí),使用if-else或者switch不論在可讀性上和性能上都不應(yīng)該去選擇,比如下面的情況:

var array = [0,1,2,3,4,5,6,7...];
switch(result){
    case 0: return array[0];
    case 1: return array[1];
    case 2: return array[2];
    case 3: return array[3];
    case 4: return array[4];
    case 5: return array[5];
    case 6: return array[6];
    ...
}

當(dāng)數(shù)組有數(shù)十個(gè)上百個(gè)數(shù)據(jù)時(shí),switch語(yǔ)句會(huì)是一段很龐大的代碼。這時(shí)候可以使用查表法:

var array = [0,1,2,3,4,5,6,7...];
return array[result];

查表法一般適用于數(shù)據(jù)量稍大的場(chǎng)合,在實(shí)際編程中,還是經(jīng)常會(huì)用到這種方法的。

d、Recursion 遞歸
某些場(chǎng)合,比如說(shuō)階乘函數(shù),遞歸調(diào)用無(wú)疑是最優(yōu)的實(shí)現(xiàn)方式:

function calc(n){
    if(n === 0){
        return 1;
    }else{
        return n * calc(n-1);
    }
}

e、Memoization 制表
制表的原理是通過(guò)緩存已經(jīng)運(yùn)行的計(jì)算結(jié)果,避免后續(xù)的重復(fù)計(jì)算從而提升性能。也常用于遞歸運(yùn)算中,例如上面的階乘函數(shù)的調(diào)用:

var a = calc(10);
var b = calc(9);
var c = calc(8);

calc(10)被調(diào)用時(shí),就已經(jīng)計(jì)算過(guò)了calc(9)calc(8)的值,這里calc(9)就重復(fù)計(jì)算了兩次,而calc(8)重復(fù)計(jì)算了三次,我們可以通過(guò)緩存計(jì)算結(jié)果的辦法去優(yōu)化:

function m(n){
    if(!m.c){
        m.c = {
            "0": 1,
            "1": 1
        };
    }
    if(!m.c.hasOwnProperty(n)){
        m.c[n] = n * m(n-1);
    }
    return m.c[n];
}
var e = m(10);
var f = m(9);
var g = m(8);

優(yōu)化后的函數(shù)中,m(9)m(8)并沒(méi)有再去計(jì)算,從而避免了重復(fù)計(jì)算。

高性能JavaScript閱讀簡(jiǎn)記(一)
高性能JavaScript閱讀簡(jiǎn)記(二)
高性能JavaScript閱讀簡(jiǎn)記(三)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/112434.html

相關(guān)文章

  • 性能JavaScript閱讀簡(jiǎn)記

    摘要:移植到中的一個(gè)典型的達(dá)夫設(shè)備的例子為一個(gè)很長(zhǎng)很長(zhǎng)的數(shù)組。但是達(dá)夫設(shè)備最初這種詭異的寫(xiě)法和思路,還是驚艷了很多人的,值得我們思考。高性能閱讀簡(jiǎn)記一高性能閱讀簡(jiǎn)記二高性能閱讀簡(jiǎn)記三 四、Aligorithms and Flow Control 算法和流程控制 1、Loops 循環(huán) a、避免使用for/in循環(huán)在JavaScript標(biāo)準(zhǔn)中,有四種類型循環(huán)。for、for/in、while、...

    psychola 評(píng)論0 收藏0
  • 性能JavaScript閱讀簡(jiǎn)記

    摘要:移植到中的一個(gè)典型的達(dá)夫設(shè)備的例子為一個(gè)很長(zhǎng)很長(zhǎng)的數(shù)組。但是達(dá)夫設(shè)備最初這種詭異的寫(xiě)法和思路,還是驚艷了很多人的,值得我們思考。高性能閱讀簡(jiǎn)記一高性能閱讀簡(jiǎn)記二高性能閱讀簡(jiǎn)記三 四、Aligorithms and Flow Control 算法和流程控制 1、Loops 循環(huán) a、避免使用for/in循環(huán)在JavaScript標(biāo)準(zhǔn)中,有四種類型循環(huán)。for、for/in、while、...

    newsning 評(píng)論0 收藏0
  • 性能JavaScript閱讀簡(jiǎn)記(一)

    摘要:對(duì)于直接量和局部變量的訪問(wèn)性能差異微不足道,性能消耗代價(jià)高一些的是全局變量數(shù)組項(xiàng)對(duì)象成員。當(dāng)一個(gè)函數(shù)被創(chuàng)建后,作用域鏈中被放入可訪問(wèn)的對(duì)象。同樣會(huì)改變作用域鏈,帶來(lái)性能問(wèn)題。 早前閱讀高性能JavaScript一書(shū)所做筆記。 一、Loading and Execution 加載和運(yùn)行 從加載和運(yùn)行角度優(yōu)化,源于JavaScript運(yùn)行會(huì)阻塞UI更新,JavaScript腳本的下載、解析...

    sorra 評(píng)論0 收藏0
  • 性能JavaScript閱讀簡(jiǎn)記(一)

    摘要:對(duì)于直接量和局部變量的訪問(wèn)性能差異微不足道,性能消耗代價(jià)高一些的是全局變量數(shù)組項(xiàng)對(duì)象成員。當(dāng)一個(gè)函數(shù)被創(chuàng)建后,作用域鏈中被放入可訪問(wèn)的對(duì)象。同樣會(huì)改變作用域鏈,帶來(lái)性能問(wèn)題。 早前閱讀高性能JavaScript一書(shū)所做筆記。 一、Loading and Execution 加載和運(yùn)行 從加載和運(yùn)行角度優(yōu)化,源于JavaScript運(yùn)行會(huì)阻塞UI更新,JavaScript腳本的下載、解析...

    zhangrxiang 評(píng)論0 收藏0
  • 性能JavaScript閱讀簡(jiǎn)記(二)

    摘要:訪問(wèn)集合元素時(shí)使用局部變量對(duì)于任何類型的訪問(wèn),如果對(duì)同一個(gè)屬性或者方法訪問(wèn)多次,最好使用一個(gè)局部變量對(duì)此成員進(jìn)行緩存。 三、DOM Scripting DOM編程 我們都知道對(duì)DOM操作的代價(jià)昂貴,這往往成為網(wǎng)頁(yè)應(yīng)用中的性能瓶頸。在解決這個(gè)問(wèn)題之前,我們需要先知道什么是DOM,為什么他會(huì)很慢。 DOM in the Browser World 瀏覽器中的DOM DOM是一個(gè)獨(dú)立于語(yǔ)言...

    RaoMeng 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

leiyi

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<