如何提升JavaScript迴圈的運行速度

來源:互聯網
上載者:User

Nicholas為您講解如何提升JavaScript迴圈的運行速度!

根 據Nicholas的說法,有四種代碼會拖慢指令碼的運行,並最終導致指令碼失控。分別是次數過多的同步迴圈、龐大的函數體、不恰當的遞迴和不合理的DOM調用。這篇著重講第一個原因。最後給出了一個開發模式,替換傳統的迴圈結構,可以完全避免指令碼失控的狀況發生。

【原文標題】Speed up your JavaScript, Part 1

【原文作者】Nicholas C. Zakas

在我上一篇文章 (譯文 ) 中,談到了各個瀏覽器究竟會在什麼情況下彈出指令碼失控提示,對於Internet Explorer來說,當瀏覽器執行了數量過多的語句時就會停止執行指令碼,而其他的瀏覽器,則是持續執行指令碼超過一定時間的時候就會給出提示。而我們要探 討的核心問題,不是這些瀏覽器如果探測失控的指令碼,而是我們如何才可以讓指令碼啟動並執行更快一些,從而避免這些警告。

 

指令碼失控基本上有以下四個方面的原因:

 

1. 在迴圈中執行了太多的操作。

 

2. 臃腫的函數體

 

3. 過多的遞迴

 

4. 過多的DOM調用

 

在 這篇文章中,我將會把重點放到第一條上:迴圈中的過多操作。迴圈的操作是同步進行的,所以執行一個迴圈所花費的時間完全取決於迴圈的次數。因此有兩種情況 會導致迴圈執行的時間過長,並直接導致鎖定瀏覽器。一是迴圈體中包含了太多的操作,二是迴圈的次數過多。這兩種情況都能直接導致鎖定瀏覽器,並顯示指令碼失 控的提示。

 

解決這個問題的訣竅就是用下面這兩個問題來評估每個迴圈:

 

1. 這個迴圈必須要同步執行嗎?

 

2. 迴圈裡面的資料,必須要按順序執行嗎?

 

如果兩個問題的答案都是否定的話,你就可以選擇將迴圈裡的操作進行分解。關鍵是要根據代碼的具體環境確定上面兩個問題的答案。一個典型的迴圈可能像下面這個樣子:

 

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

乍 一看這個迴圈並沒有太大的問題,是不是會運行很長時間完全取決於迴圈的次數。如果緊接迴圈後沒有其他代碼在執行的時候需要依賴於迴圈的結果,那麼對於第一 個問題的答案就是“不”。你還可以發現,迴圈每次只處理一個數值,而且不依賴於上一次迴圈的結果,所以對於第二個問題的答案同樣也是否定的。這就意味著, 迴圈可以通過某種方式進行拆解,不會導致鎖定瀏覽器而顯示指令碼失控的提示。

 

在《Professional JavaScript, Second Edition 》這本書中,對於那些執行次數非常巨大的虛幻,我推薦使用下面的方式來處理:

 

function chunk(array, process, context){
setTimeout(function(){
var item = array.shift();
process.call(context, item);

if (array.length > 0){
setTimeout(arguments.callee, 100);
}
}, 100);
}

chunk() 函數的用途就是將一個數組分成小塊處理(這也是名字的由來),我們可以傳遞三個參數。要處理的數組對象、處理函數以及一個可選的上下文變數,用於設定 process()函數中對應的this對象。第一個timer用於處理操作之間的延時(這裡設定為100毫秒,大家可以根據實際需要自行修改)。每次執 行這個函數,都會將數組中的第一個對象取出,並傳給process()函數進行操作,如果這時process()中還有未處理完的對象,另外一個 timer就會啟動,用於重複等待。上面提到的迴圈,可以通過下面的方法使用這個函數:

 

chunk(items, process); 

需要注意的是,在這裡數組採用了隊列(queue)的形式,而且在迴圈的過程中,每次都會發生修改。如果你要修改數組的原始狀態,這裡介紹兩種途徑:一種是通過concat()函數,在傳遞之前,建立一個當前數組的副本:

 

chunk(items.concat(), process); 

另外一種選擇是直接修改chunk()函數,直接在函數內部進行修改:

 

function chunk(array, process, context){
var items = array.concat(); //clone the array
setTimeout(function(){
var item = items.shift();
process.call(context, item);

if (items.length > 0){
setTimeout(arguments.callee, 100);
}
}, 100);
}

注意這種方法要比只儲存一個索引安全的多,因為數組的內容在下次計時器生效之前可能會發生變化。

 

這 裡提到的chunk()函數,只是最佳化迴圈效能的一個起點。你可以根據需要不斷改進它,讓它擁有更多的功能。比如說,在數組中所有對象都處理完成以後,可 以增加一個函數回調。無論你是否會按照這種方式對函數進行修改,這隻是一種JavaScript的代碼開發模式,可以協助最佳化數組的處理效能,還可以避免 那個指令碼失控的警告。

 

未知來源 歡迎告之
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.