最近在看《高效能網站建設進階指南》,第七章為《編寫高效的javascript》,作者為Nicholas C. Zakas(同時也是《javascript進階程式設計》的作者),裡面講到字串串連的最佳化問題。
字串串連一直是javascript中效能最低的操作之一,通常情況下,字串串連是通過使用加法運算子(+)來實現的,比方說
var text="hello";
text+=" ";
text+="world!";
早期瀏覽器沒有對這種運算進行最佳化。由於字串是不可變的,這意味著要建立中間字串來儲存串連的結果。參照《javascript進階程式設計》,大致要經過以下幾個步驟:
建立儲存"hello"的字串。
建立儲存"world"的字串。
建立儲存串連結果的字串。
把str的當前內容複寫到結果中。
把"world "複製到結果中。
更新str,使它指向結果。
頻繁地在後台建立和銷毀字串會導致字串串連的效能異常低下。
好在如今大部分瀏覽器已經對字串串連進行了最佳化。第一款進行最佳化的瀏覽器是Firefox,從1.0版本開始,在所有情況下使用數組技術實際上都比使用加法運算慢。其他瀏覽器也最佳化了字串串連,Safari、Opera、Chrome和Internet Explorer8也都在使用加法運算子上表現出了更好的效能。(PS:在Ie8之前的版本沒有進行最佳化)
那麼,在瀏覽器還未對字串串連效能進行最佳化之前,該怎麼改進其效能呢?其中一種普遍使用的方法就是使用Array對象,方法如下:
function StringBuffer(){
this._strings=new Array();
}
StringBuffer.prototype.append=function(str){
this._strings.push(str)
}
StringBuffer.prototype.toString=function(){
return this._strings.join("");
}
這樣,無論在數組中引入多少字串都不成問題,因為只有在調用join()方法時才會發生串連操作,此時步驟如下:
建立儲存結果的數組
把每個字串複製到結果中的合適位置
將數組合并成字串返回
經過測試,採用上述方法,在Firefox 3.6中以及Ie 8中,效能其實比直接用加法運算子(+)效率要低(上文說過現在大部分主流瀏覽器都已經經過最佳化),然而,在IE 8之前版本的IE瀏覽器中,採用這種方法連接字串,效能比直接用加法運算子(+)有很大的提高,大概是60%左右(也就是花費的時間為原來的1/3左右),用的是《javascript進階程式設計》裡的測試代碼:
var d1=new Date();
var str="";
for(var i=0;i<10000;i++){
str+="text";
}
var d2=new Date();
var d3=d2.getTime()-d1.getTime();
var buffer=new StringBuffer();
d1=new Date();
for(var j=0;j<10000;j++){
buffer.append("text");
}
var result=buffer.toString();
d2=new Date();
var d4=d2.getTime()-d1.getTime();
alert("d3:"+d3+" d4:"+d4);
以下是Nicholas C. Zakas大牛對決定如何連接字串的建議,需要考慮兩個因素:(1)被串連的字串大小(2)數量
當字串較小(少於20個字元)且串連的數量也較小時(少於1000個),所有的瀏覽器中使用的加法運算子都能在不到1毫秒之內輕鬆完成串連。在這種情況下就沒有理由去考慮加法運算子以外的方式了。
增加連接字串的數量或大小時,在IE 7中效能會明顯下降。當字串大小增加時,在Firefox中加法運算子和數組技術的效能差異會變小。當字串串連數量增加時,在Safari中這兩種技術的新能差異也同樣會變小。只有Chrome和Opera在改變連接字串的大小和數量時,加法運算子一直保持著顯著的效能優勢。
由於在各瀏覽器下效能不一致,所以選用哪種技術在很大程度上取決與實際情況和面對的瀏覽器。如果使用者主要使用IE 6或7,那麼使用數組技術就很值得,因為這會影響大多數人。(備忘:目前國內使用IE 6的人不少。。。)通常使用數組技術在其他瀏覽器中的效能損失要遠小於在IE中的效能提升,所以要基於使用者的瀏覽器來權衡使用者體驗,而不要視圖去針對某種具體情況或瀏覽器版本。不過,在大多數情況下,加法運算子也是首選的。