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

資訊專欄INFORMATION COLUMN

前端性能優(yōu)化(JavaScript篇)

kun_jian / 3205人閱讀

摘要:像也是類似的也不建議使用,會(huì)降低性能,通過(guò)包裹的代碼塊,作用域鏈將會(huì)額外增加一層,降低索引效率對(duì)象的優(yōu)化緩存需要被使用的對(duì)象獲取數(shù)據(jù)的性能有如下順序從快到慢變量獲取數(shù)組下標(biāo)獲取對(duì)象的整數(shù)索引獲取對(duì)象屬性獲取對(duì)象非整數(shù)索引獲取。

正巧看到在送書(shū),于是乎找了找自己博客上記錄過(guò)的一些東西來(lái)及其無(wú)恥的蹭書(shū)了~~~

小廣告:更多內(nèi)容可以看我的博客

優(yōu)化循環(huán)

如果現(xiàn)在有個(gè)一個(gè)data[]數(shù)組,需要對(duì)其進(jìn)行遍歷,應(yīng)當(dāng)怎么做?最簡(jiǎn)單的代碼是:

for (var i = 0; i < data.length; i++) {
    //do someting
}

這里每次循環(huán)開(kāi)始前都需要判斷i是否小于data.length,JavaScript并不會(huì)對(duì)data.length進(jìn)行緩存,而是每次比較都會(huì)進(jìn)行一次取值。如我們所知,JavaScript數(shù)組其實(shí)是一個(gè)對(duì)象,里面有個(gè)length屬性,所以這里實(shí)際上就是取得對(duì)象的屬性。如果直接使用變量的話就會(huì)少一次索引對(duì)象,如果數(shù)組的元素很多,效率提升還是很可觀的。所以我們通常將代碼改成如下所示:

for(var i = 0, m = data.length; i < m; i++) {
    //do someting
}

這里多加了一個(gè)變量m用于存放data.length屬性,這樣就可以在每次循環(huán)時(shí),減少一次索引對(duì)象,但是代價(jià)是增加了一個(gè)變量的空間,如果遍歷不要求順序,我們甚至可以不用m這個(gè)變量存儲(chǔ)長(zhǎng)度,在不要求順序的時(shí)候可以使用如下代碼:

for(var i = data.length; i--; ) {
    //do someting
}

當(dāng)然我們可以使用while來(lái)替代:

var i = data.length;
while(i--) {
    //do someting
}

這樣就可只使用一個(gè)變量了

運(yùn)算結(jié)果緩存

由于JavaScript中的函數(shù)也是對(duì)象(JavaScript中一切都是對(duì)象),所以我們可以給函數(shù)添加任意的屬性。這也就為我們提供符合備忘錄模式的緩存運(yùn)算結(jié)果的功能,比如我們有一個(gè)需要大量運(yùn)算才能得出結(jié)果的函數(shù)如下:

function calculator(params) {
    //大量的耗時(shí)的計(jì)算 
    return result;
}

如果其中不涉及隨機(jī),參數(shù)一樣時(shí)所返回的結(jié)果一致,我們就可以將運(yùn)算結(jié)果進(jìn)行緩存從而避免重復(fù)的計(jì)算:

function calculator(params) {
    var cacheKey = JSON.stringify(params);
    var cache = calculator.cache = calculator.cache || {};
    if(typeof cache[cacheKey] !== "undefined") {
        return cache[cacheKey];
    }
    //大量耗時(shí)的計(jì)算
    cache[cacheKey] = result;
    return result;
}

這里將參數(shù)轉(zhuǎn)化為JSON字符串作為key,如果這個(gè)參數(shù)已經(jīng)被計(jì)算過(guò),那么就直接返回,否則進(jìn)行計(jì)算。計(jì)算完畢后再添加入cache中,如果需要,可以直接查看cache的內(nèi)容:calculator.cache

這是一種典型的空間換時(shí)間的方式,由于瀏覽器的頁(yè)面存活時(shí)間一般不會(huì)很長(zhǎng),占用的內(nèi)存會(huì)很快被釋放(當(dāng)然也有例外,比如一些WEB應(yīng)用),所以可以通過(guò)這種空間換時(shí)間的方式來(lái)減少響應(yīng)時(shí)間,提升用戶體驗(yàn)。這種方式并不適用于如下場(chǎng)合:
1. 相同參數(shù)可能產(chǎn)生不同結(jié)果的情況(包含隨機(jī)數(shù)之類的)
2. 運(yùn)算結(jié)果占用特別多內(nèi)存的情況

不要在循環(huán)中創(chuàng)建函數(shù)

這個(gè)很好理解,每創(chuàng)建一個(gè)函數(shù)對(duì)象是需要大批量空間的。所以在一個(gè)循環(huán)中創(chuàng)建函數(shù)是很不明智的,盡量將函數(shù)移動(dòng)到循環(huán)之前創(chuàng)建,比如如下代碼:

for(var i = 0, m = data.length; i < m; i++) {
    handlerData(data[i], function(data){
        //do something
    });
}

就可以修改為:

var handler = function(data){
    //do something
};
for(var i = 0, m = data.length; i < m; i++) {
    handlerData(data[i], handler);
}
讓垃圾回收器回收那些不再需要的對(duì)象

之前我曾在 淺談V8引擎中的垃圾回收機(jī)制 中講到了V8引擎如何進(jìn)行垃圾回收。可以從中看到,如果長(zhǎng)時(shí)間保存對(duì)象,老生代中占用的空間將增大,每次在老生代中的垃圾回收過(guò)程將會(huì)相當(dāng)漫長(zhǎng)。而垃圾回收器判斷一個(gè)對(duì)象為活對(duì)象還是死對(duì)象,是按照是否有活對(duì)象或根對(duì)象含有對(duì)它的引用來(lái)判定的。如果有根對(duì)象或者活對(duì)象引用了這個(gè)對(duì)象,它將被判定為活對(duì)象。所以我們需要通過(guò)手動(dòng)消除這些引用來(lái)讓垃圾回收器對(duì)回收這些對(duì)象。

delete

一種方式是通過(guò)delete方式來(lái)消除對(duì)象中的鍵值對(duì),從而消除引用。但這種方式并不提倡,它會(huì)改變對(duì)象的結(jié)構(gòu),可能導(dǎo)致引擎中對(duì)對(duì)象的存儲(chǔ)方式變更,降級(jí)為字典方式進(jìn)行存儲(chǔ)(詳細(xì)請(qǐng)見(jiàn)V8 之旅:對(duì)象表示),不利于JavaScript引擎的優(yōu)化,所以盡量減少使用

null

另一種方式是通過(guò)將值設(shè)為null來(lái)消除引用。通過(guò)將變量或?qū)ο蟮膶傩栽O(shè)為null,可以消除引用,使原本引用的對(duì)象成為一個(gè)“孤島”,然后在垃圾回收的時(shí)候?qū)ζ溥M(jìn)行回收。這種方式不會(huì)改變對(duì)象的結(jié)構(gòu),比使用delete要好

全局對(duì)象

另外需要注意的是,垃圾回收器認(rèn)為根對(duì)象永遠(yuǎn)是活對(duì)象,永遠(yuǎn)不會(huì)對(duì)其進(jìn)行垃圾回收。而全局對(duì)象就是根對(duì)象,所以全局作用域中的變量將會(huì)一直存在

事件處理器的回收

在平常寫(xiě)代碼的時(shí)候,我們經(jīng)常會(huì)給一個(gè)DOM節(jié)點(diǎn)綁定事件處理器,但有時(shí)候我們不需要這些事件處理器后,就不管它們了,它們默默的在內(nèi)存中保存著。所以在某些DOM節(jié)點(diǎn)綁定的事件處理器不需要后,我們應(yīng)當(dāng)銷毀它們。同時(shí)綁定的時(shí)候也盡量使用事件代理的方式進(jìn)行綁定,以免造成多次重復(fù)的綁定導(dǎo)致內(nèi)存空間的浪費(fèi),事件代理可見(jiàn)前端性能優(yōu)化(DOM操作篇)

閉包導(dǎo)致的內(nèi)存泄露

JavaScript的閉包可以說(shuō)即是“天使”又是“魔鬼”,它“天使”的一面是我們可以通過(guò)它突破作用域的限制,而其魔鬼的一面就是和容易導(dǎo)致內(nèi)存泄露,比如如下情況:

var result = (function() {
    var small = {};
    var big = new Array(10000000);
    //do something
    return function(){
        if(big.indexOf("someValue") !== -1) {
            return null;
        } else {
            return small;
        }
    }
})();

這里,創(chuàng)建了一個(gè)閉包。使得返回的函數(shù)存儲(chǔ)在result中,而result函數(shù)能夠訪問(wèn)其作用域內(nèi)的small對(duì)象和big對(duì)象。由于big對(duì)象和small對(duì)象都可能被訪問(wèn),所以垃圾回收器不會(huì)去碰這兩個(gè)對(duì)象,它們不會(huì)被回收。我們將上述代碼改成如下形式:

var result = (function() {
    var small = {};
    var big = new Array(10000000);
    var hasSomeValue;
    //do something
    hasSomeValue = big.indexOf("someValue") !== -1;
    return function(){
        if(hasSomeValue) {
            return null;
        } else {
            return small;
        }
    }
})();

這樣,函數(shù)內(nèi)部只能夠訪問(wèn)到hasSomeValue變量和small變量了,big沒(méi)有辦法通過(guò)任何形式被訪問(wèn)到,垃圾回收器將會(huì)對(duì)其進(jìn)行回收,節(jié)省了大量的內(nèi)存。

慎用eval和with

Douglas Crockford將eval比作魔鬼,確實(shí)在很多方面我們可以找到更好地替代方式。使用它時(shí)需要在運(yùn)行時(shí)調(diào)用解釋引擎對(duì)eval()函數(shù)內(nèi)部的字符串進(jìn)行解釋運(yùn)行,這需要消耗大量的時(shí)間。像FunctionsetIntervalsetTimeout也是類似的

Douglas Crockford也不建議使用with,with會(huì)降低性能,通過(guò)with包裹的代碼塊,作用域鏈將會(huì)額外增加一層,降低索引效率

對(duì)象的優(yōu)化 緩存需要被使用的對(duì)象

JavaScript獲取數(shù)據(jù)的性能有如下順序(從快到慢):變量獲取 > 數(shù)組下標(biāo)獲取(對(duì)象的整數(shù)索引獲取) > 對(duì)象屬性獲取(對(duì)象非整數(shù)索引獲取)。我們可以通過(guò)最快的方式代替最慢的方式:

var body = document.body;
var maxLength = someArray.length;
//...

需要考慮,作用域鏈和原型鏈中的對(duì)象索引。如果作用域鏈和原型鏈較長(zhǎng),也需要對(duì)所需要的變量繼續(xù)緩存,否則沿著作用域鏈和原型鏈向上查找時(shí)也會(huì)額外消耗時(shí)間

緩存正則表達(dá)式對(duì)象

需要注意,正則表達(dá)式對(duì)象的創(chuàng)建非常消耗時(shí)間,盡量不要在循環(huán)中創(chuàng)建正則表達(dá)式,盡可能多的對(duì)正則表達(dá)式對(duì)象進(jìn)行復(fù)用

考慮對(duì)象和數(shù)組

在JavaScript中我們可以使用兩種存放數(shù)據(jù):對(duì)象和數(shù)組。由于JavaScript數(shù)組可以存放任意類型數(shù)據(jù)這樣的靈活性,導(dǎo)致我們經(jīng)常需要考慮何時(shí)使用數(shù)組,何時(shí)使用對(duì)象。我們應(yīng)當(dāng)在如下情況下做出考慮:
1. 存儲(chǔ)一串相同類型的對(duì)象,應(yīng)當(dāng)使用數(shù)組
2. 存儲(chǔ)一堆鍵值對(duì),值的類型多樣,應(yīng)當(dāng)使用對(duì)象
3. 所有值都是通過(guò)整數(shù)索引,應(yīng)當(dāng)使用數(shù)組

數(shù)組使用時(shí)的優(yōu)化

往數(shù)組中插入混合類型很容易降低數(shù)組使用的效率,盡量保持?jǐn)?shù)組中元素的類型一致

如果使用稀疏數(shù)組,它的元素訪問(wèn)將遠(yuǎn)慢于滿數(shù)組的元素訪問(wèn)。因?yàn)閂8為了節(jié)省空間,會(huì)將稀疏數(shù)組通過(guò)字典方式保存在內(nèi)存中,節(jié)約了空間,但增加了訪問(wèn)時(shí)間

對(duì)象的拷貝

需要注意的是,JavaScript遍歷對(duì)象和數(shù)組時(shí),使用for...in的效率相當(dāng)?shù)停栽诳截悓?duì)象時(shí),如果已知需要被拷貝的對(duì)象的屬性,通過(guò)直接賦值的方式比使用for...in方式要來(lái)得快,我們可以通過(guò)定一個(gè)拷貝構(gòu)造函數(shù)來(lái)實(shí)現(xiàn),比如如下代碼:

function copy(source){
    var result = {};
    var item;
    for(item in source) {
        result[item] = source[item];
    }
    return result;
}
var backup = copy(source);

可修改為:

function copy(source){
    this.property1 = source.property1;
    this.property2 = source.property2;
    this.property3 = source.property3;
    //...
}
var backup = new copy(source);
字面量代替構(gòu)造函數(shù)

JavaScript可以通過(guò)字面量來(lái)構(gòu)造對(duì)象,比如通過(guò)[]構(gòu)造一個(gè)數(shù)組,{}構(gòu)造一個(gè)對(duì)象,/regexp/構(gòu)造一個(gè)正則表達(dá)式,我們應(yīng)當(dāng)盡力使用字面量來(lái)構(gòu)造對(duì)象,因?yàn)樽置媪渴且嬷苯咏忉寛?zhí)行的,而如果使用構(gòu)造函數(shù)的話,需要調(diào)用一個(gè)內(nèi)部構(gòu)造器,所以字面量略微要快一點(diǎn)點(diǎn)。

緩存AJAX

曾經(jīng)聽(tīng)過(guò)一個(gè)訪問(wèn)時(shí)間比較(當(dāng)然不精確):
* cpu cache ≈ 100 * 寄存器
* 內(nèi)存 ≈ 100 * cpu cache
* 外存 ≈ 100 * 內(nèi)存
* 網(wǎng)絡(luò) ≈ 100 * 外存

可看到訪問(wèn)網(wǎng)絡(luò)資源是相當(dāng)慢的,而AJAX就是JavaScript訪問(wèn)網(wǎng)絡(luò)資源的方式,所以對(duì)一些AJAX結(jié)果進(jìn)行緩存,可以大大減少響應(yīng)時(shí)間。那么如何緩存AJAX結(jié)果呢

函數(shù)緩存

我們可以使用前面緩存復(fù)雜計(jì)算函數(shù)結(jié)果的方式進(jìn)行緩存,通過(guò)在函數(shù)對(duì)象上構(gòu)造cache對(duì)象,原理一樣,這里略過(guò)。這種方式是精確到函數(shù),而不精確到請(qǐng)求

本地緩存

HTML5提供了本地緩存sessionStorage和localStorage,區(qū)別就是前者在瀏覽器關(guān)閉后會(huì)自動(dòng)釋放,而后者則是永久的,不會(huì)被釋放。它提供的緩存大小以MB為單位,比cookie(4KB)要大得多,所以我們可以根據(jù)AJAX數(shù)據(jù)的存活時(shí)間來(lái)判斷是存放在sessionStorage還是localStorage當(dāng)中,在這里以存儲(chǔ)到sessionStorage中為例(localStorage只需把第一行的window.sessionStorage修改為window.localStorage):

function(data, url, type, callback){
    var storage = window.sessionStorage;
    var key = JSON.stringify({
        url : url,
        type : type,
        data : data
    });
    var result = storage.getItem(key);
    var xhr;
    if (result) {
        callback.call(null, result);
    } else {
        xhr.onreadystatechange = function(){
            if(xhr.readyState === 4){
                if(xhr.status === 200){
                    storage.setItem(key, xhr.responseText);
                    callback.call(null, xhr.responseText);
                } else {
                }
            }
        };
        xhr.open(type, url, async);
        xhr.send(data);
    }
};
使用布爾表達(dá)式的短路

在很多語(yǔ)言中,如果bool表達(dá)式的值已經(jīng)能通過(guò)前面的條件確定,那么后面的判斷條件將不再會(huì)執(zhí)行,比如如下代碼

function calCondition(params) {
    var result;
    //do lots of work
    return !!result;
}

if(otherCondition && calCondition(someParams)) {
    console.log(true);
} else {
    console.log(false);
}

這里首先會(huì)計(jì)算otherCondition的值,如果它為false,那么整個(gè)正則表達(dá)式就為false了,后續(xù)的需要消耗大量時(shí)間的calCondition()函數(shù)就不會(huì)被調(diào)用和計(jì)算了,節(jié)省了時(shí)間

使用原生方法

在JavaScript中,大多數(shù)原生方法是使用C++編寫(xiě)的,比js寫(xiě)的方法要快得多,所以盡量使用諸如Math之類的原生對(duì)象和方法

字符串拼接

在IE和FF下,使用直接+=的方式或是+的方式進(jìn)行字符串拼接,將會(huì)很慢。我們可以通過(guò)Array的join()方法進(jìn)行字符串拼接。不過(guò)并不是所有瀏覽器都是這樣,現(xiàn)在很多瀏覽器使用+=比join()方法還要快

使用web worker

web worker是HTML5提出的一項(xiàng)新技術(shù),通過(guò)多線程的方式為JavaScript提供并行計(jì)算的能力,通過(guò)message的方式進(jìn)行相互之間的信息傳遞,我還沒(méi)有仔細(xì)研究過(guò)

JavaScript文件的優(yōu)化 使用CDN

在編寫(xiě)JavaScript代碼中,我們經(jīng)常會(huì)使用庫(kù)(jQuery等等),這些JS庫(kù)通常不會(huì)對(duì)其進(jìn)行更改,我們可以將這些庫(kù)文件放在CDN(內(nèi)容分發(fā)網(wǎng)絡(luò)上),這樣能大大減少響應(yīng)時(shí)間

壓縮與合并JavaScript文件

在網(wǎng)絡(luò)中傳輸JS文件,文件越長(zhǎng),需要的時(shí)間越多。所以在上線前,通常都會(huì)對(duì)JS文件進(jìn)行壓縮,去掉其中的注釋、回車、不必要的空格等多余內(nèi)容,如果通過(guò)uglify的算法,還可以縮減變量名和函數(shù)名,從而將JS代碼壓縮,節(jié)約傳輸時(shí)的帶寬。另外經(jīng)常也會(huì)將JavaScript代碼合并,使所有代碼在一個(gè)文件之中,這樣就能夠減少HTTP的請(qǐng)求次數(shù)。合并的原理和sprite技術(shù)相同

使用Application Cache緩存

這個(gè)在之前的文章前端性能優(yōu)化(Application Cache篇)中已有描述,就不贅述了

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

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

相關(guān)文章

  • 前端資源系列(4)-前端學(xué)習(xí)資源分享&前端面試資源匯總

    摘要:特意對(duì)前端學(xué)習(xí)資源做一個(gè)匯總,方便自己學(xué)習(xí)查閱參考,和好友們共同進(jìn)步。 特意對(duì)前端學(xué)習(xí)資源做一個(gè)匯總,方便自己學(xué)習(xí)查閱參考,和好友們共同進(jìn)步。 本以為自己收藏的站點(diǎn)多,可以很快搞定,沒(méi)想到一入?yún)R總深似海。還有很多不足&遺漏的地方,歡迎補(bǔ)充。有錯(cuò)誤的地方,還請(qǐng)斧正... 托管: welcome to git,歡迎交流,感謝star 有好友反應(yīng)和斧正,會(huì)及時(shí)更新,平時(shí)業(yè)務(wù)工作時(shí)也會(huì)不定期更...

    princekin 評(píng)論0 收藏0
  • 王下邀月熊_Chevalier的前端每周清單系列文章索引

    摘要:感謝王下邀月熊分享的前端每周清單,為方便大家閱讀,特整理一份索引。王下邀月熊大大也于年月日整理了自己的前端每周清單系列,并以年月為單位進(jìn)行分類,具體內(nèi)容看這里前端每周清單年度總結(jié)與盤(pán)點(diǎn)。 感謝 王下邀月熊_Chevalier 分享的前端每周清單,為方便大家閱讀,特整理一份索引。 王下邀月熊大大也于 2018 年 3 月 31 日整理了自己的前端每周清單系列,并以年/月為單位進(jìn)行分類,具...

    2501207950 評(píng)論0 收藏0
  • 前端優(yōu)化 - 收藏集 - 掘金

    摘要:雖然有著各種各樣的不同,但是相同的是,他們前端優(yōu)化不完全指南前端掘金篇幅可能有點(diǎn)長(zhǎng),我想先聊一聊閱讀的方式,我希望你閱讀的時(shí)候,能夠把我當(dāng)作你的競(jìng)爭(zhēng)對(duì)手,你的夢(mèng)想是超越我。 如何提升頁(yè)面渲染效率 - 前端 - 掘金Web頁(yè)面的性能 我們每天都會(huì)瀏覽很多的Web頁(yè)面,使用很多基于Web的應(yīng)用。這些站點(diǎn)看起來(lái)既不一樣,用途也都各有不同,有在線視頻,Social Media,新聞,郵件客戶端...

    VincentFF 評(píng)論0 收藏0
  • 前端性能優(yōu)化JavaScript

    摘要:減少作用域鏈上的查找次數(shù)。盡量少用全局變量,盡量使用局部變量。全局變量如果不手動(dòng)銷毀,會(huì)一直存在,造成全局變量污染,可能很產(chǎn)生一些意想不到的錯(cuò)誤,而局部變量運(yùn)行完成后,就被會(huì)被回收使用代替大量的內(nèi)聯(lián)樣式修改。性能優(yōu)化還需要繼續(xù)深入研究。 關(guān)于前端性能優(yōu)化的討論一直都很多,包羅的知識(shí)也很多,可以說(shuō)性能優(yōu)化只有更好,沒(méi)有最好。前面我寫(xiě)了一篇關(guān)于css優(yōu)化的總結(jié)文章,今天再?gòu)膉avascri...

    chuyao 評(píng)論0 收藏0
  • 前端性能優(yōu)化JavaScript

    摘要:減少作用域鏈上的查找次數(shù)。盡量少用全局變量,盡量使用局部變量。全局變量如果不手動(dòng)銷毀,會(huì)一直存在,造成全局變量污染,可能很產(chǎn)生一些意想不到的錯(cuò)誤,而局部變量運(yùn)行完成后,就被會(huì)被回收使用代替大量的內(nèi)聯(lián)樣式修改。性能優(yōu)化還需要繼續(xù)深入研究。 關(guān)于前端性能優(yōu)化的討論一直都很多,包羅的知識(shí)也很多,可以說(shuō)性能優(yōu)化只有更好,沒(méi)有最好。前面我寫(xiě)了一篇關(guān)于css優(yōu)化的總結(jié)文章,今天再?gòu)膉avascri...

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

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

0條評(píng)論

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