如何提升JavaScript函數的運行速度

來源:互聯網
上載者:User

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

這 篇是Nicholas討論如果防止指令碼失控的第二篇,主要討論了如何重構嵌套循 環、遞迴,以及那些在函數內部同時執行很多子操作的函數。基本的思想和上一節trunk()那個例子一致,如果幾個操作沒有特定的執行順序,而且互相不是 依賴關係,我們就可以通過非同步呼叫的方式加以執行,不止可以減少執行的次數,還可以防止指令碼失控。本文還介紹了通過memoization技術取代遞迴的 方法。

【原文標題】Speed up your JavaScript, Part 2
【原文作者】Nicholas C. Zakas

上周我在《too much happening in a loop 》(譯文 )這篇文章中介紹了JavaScript已耗用時間過長的第一個原因。相似的情況有時也出現在函數的定義上,函數也可能因為使用不當而過載使用。通常情況是函數內包含了過多的迴圈(不是在迴圈中執行了過多的內容),太多的遞迴,或者只不過是太多不相干但又要一起執行的操作。

太 多的迴圈經常是以嵌套的形式出現,這種代碼會一直佔用JavaScript引擎直至迴圈結束。這方面有一個非常著名的例子,就是使用冒泡演算法排序。由於 JavaScript有內建的sort()方法,我們沒有必要使用這種方式進行排序,但我們可以藉助這個演算法理解嵌套迴圈佔用資源的癥結所在,從而避免類 似情況的發生。下面是一個在JavaScript使用冒泡排序法的典型例子:

function bubbleSort(items) {
for (var i = items.length - 1; i >= 0; i--) {
for (var j = i; j >= 0; j--) {
if (items[j] < items[j - 1]) {
var temp = items[j];
items[j] = items[j - 1];
items[j - 1] = temp;
}
}
}
}

回 憶一下你在學校學習的電腦知識,你可能記得冒泡排序法是效率最低的排序演算法之一,原因是對於一個包含n個元素的數組,必須要進行n的平方次的迴圈操作。 如果數組中的元素數非常大,那麼這個操作會持續很長時間。內迴圈的操作很簡單,只是負責比較和交換數值,導致問題的最大原因在於迴圈執行的次數。這會導致 瀏覽器運行異常,潛在的直接結果就是那個指令碼失控的警告對話方塊。

幾年前,Yahoo的研究員Julien Lecomte寫了一篇題為《Running CPU Intensive JavaScript Computations in a Web Browser 》的文章,在這篇文章中作者闡述了如何將很大的javaScript操作分解成若干小部分。其中一個例子就是將冒泡排序法分解成多個步驟,每個步驟只遍曆一次數組。我對他的代碼做了改進,但方法的思路還是一樣的:

function bubbleSort(array, onComplete) {
var pos = 0; (function() {
var j, value;
for (j = array.length; j > pos; j--) {
if (array[j] < array[j - 1]) {
value = data[j];
data[j] = data[j - 1];
data[j - 1] = value;
}
}
pos++;
if (pos < array.length) {
setTimeout(arguments.callee, 10);
} else {
onComplete();
}
})();
}

這 個函數藉助一個非同步管理器來實現了冒泡演算法,在每次遍曆數組以前暫停一下。onComplete()函數會在數組排序完成後觸發,提示使用者資料已經準備 好。bubbleSort()函數使用了和chunk()函數一樣的基本技術(參考我的上一篇文章),將行為封裝在一個匿名函數中,將 arguments.callee傳遞給setTimeout()以達到重複操作的目的,直至排序完成。如果你要將嵌套的迴圈拆解成若干個小步驟,以達到 解放瀏覽器的目的,這個函數提供了不錯的指導意見。

相似的問題還包括過多的遞迴。每個額外的遞迴調用都會佔用更多的記憶體,從而減慢瀏覽器的運行。惱人的是,你可能在瀏覽器發出指令碼失控警告之前,就耗盡了系統的記憶體,導致瀏覽器處於停止回應的狀態。Crockford在部落格上曾經對這個問題 進行過深入的討論。他當時使用的例子,就是用遞迴產生一個斐波那契數列。

function fibonacci(n) {
return n < 2 ? n: fibonacci(n - 1) + fibonacci(n - 2);
};

按照Crockford的說法,執行fibonacci(40)這條語句將重複調用自身331160280次。避免使用遞迴的方案之一就是使用memoization 技術,這項技術可以擷取上一次調用的執行結果。Crockford介紹了下面這個函數,可以為處理數值的函數增加這項功能:

function memoizer(memo, fundamental) {
var shell = function (n) {
var result = memo[n];
if (typeof result !== 'number') {
result = fundamental(shell, n);
memo[n] = result;
}
return result;
};
return shell;
};

他接下來將這個函數應用在斐波那契數列產生器上:

var fibonacci = memoizer([0, 1],
function(recur, n) {
return recur(n - 1) + recur(n - 2);
});

這時如果我們再次調用fibonacci(40),只會重複調用40次,和原來相比提高得非常多。memoization的原理,概括起來就一句話,同樣的結果,你沒有必要計算兩次。如果一個結果你可能會再次使用,把這個結果儲存起來,總比重新計算一次來的快。

最後一個可能讓函數執行緩慢的原因,就是我們之前提到過的,函數裡面執行了太多的內容,通常是因為使用了類似下面的開發模式:

function doAlot() {
doSomething();
doSomethingElse();
doOneMoreThing();
}

在這裡要執行三個不同的函數,請注意,無論是哪個函數,在執行過程中都不依賴其他的函數,他們在本質是相對獨立的,只是需要在一個特定時間逐一執行而已。同樣,你可以使用類似chunk()的方法來執行一系列函數,而不會導致鎖定瀏覽器。

function schedule(functions, context) {
setTimeout(function() {
var process = functions.shift();
process.call(context);
if (functions.length > 0) {
setTimeout(arguments.callee, 100);
}
},
100);
}

schedule函數有兩個參數,一個是包含要執行函數的數組,另外一個是標明this所屬的內容物件。函數數組以隊列方式實現,Timer事件每次觸發的時候,都會將隊列最前面的函數取出並執行,這個函數可以通過下面的方式執行一系列函數:

schedule([doSomething, doSomethingElse, doOneMoreThing], window); 

很希望各個JavaScript的類庫都增加類似這樣的進程處理函數。YUI在3.0時就已經引入了Queue 對象,可以通過timer連續調用一組函數。

無 論現有的技術可以協助我們將複雜的進程拆分到什麼程度,對於開發人員來說,使用這種方法來理解並確定指令碼失控的瓶頸是非常重要的。無論是太多的迴圈、遞迴還 是其他的什麼,你現在應該知道如果處理類似的情況。但要記住,這裡提到的技術和函數只是起到拋磚引玉的作用,在實際的應用中,你應該對它們加以改進,這樣 才能發揮更大的作用。

 

未知來源 歡迎告之

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.