相似的問(wèn)題還包括過(guò)多的遞歸。每個(gè)額外的遞歸調(diào)用都會(huì)占用更多的內(nèi)存,從而減慢瀏覽器的運(yùn)行。惱人的是,你可能在瀏覽器發(fā)出腳本失控警告之前,就耗盡了系統(tǒng)的內(nèi)存,導(dǎo)致瀏覽器處于停止響應(yīng)的狀態(tài)。Crockford在博客上曾經(jīng)對(duì)這個(gè)問(wèn)題進(jìn)行過(guò)深入的討論。他當(dāng)時(shí)使用的例子,就是用遞歸生成一個(gè)斐波那契數(shù)列。
function fibonacci(n) { return n < 2 ? n: fibonacci(n - 1) + fibonacci(n - 2); };
按照Crockford的說(shuō)法,執(zhí)行fibonacci(40)這條語(yǔ)句將重復(fù)調(diào)用自身331160280次。避免使用遞歸的方案之一就是使用memoization技術(shù),這項(xiàng)技術(shù)可以獲取上一次調(diào)用的執(zhí)行結(jié)果。Crockford介紹了下面這個(gè)函數(shù),可以為處理數(shù)值的函數(shù)增加這項(xiàng)功能:
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; };
他
接下來(lái)將這個(gè)函數(shù)應(yīng)用在斐波那契數(shù)列生成器上:
var fibonacci = memoizer([0, 1], function(recur, n) { return recur(n - 1) + recur(n - 2); });
這時(shí)如果我們?cè)俅握{(diào)用fibonacci(40),只會(huì)重復(fù)調(diào)用40次,和原來(lái)相比提高得非常多。memoization的原理,概括起來(lái)就一句話(huà),同樣的結(jié)果,你沒(méi)有必要計(jì)算兩次。如果一個(gè)結(jié)果你可能會(huì)再次使用,把這個(gè)結(jié)果保存起來(lái),總比重新計(jì)算一次來(lái)的快。
最后一個(gè)可能讓函數(shù)執(zhí)行緩慢的原因,就是我們之前提到過(guò)的,函數(shù)里面執(zhí)行了太多的內(nèi)容,通常是因?yàn)槭褂昧祟?lèi)似下面的開(kāi)發(fā)模式:
function doAlot() { doSomething(); doSomethingElse(); doOneMoreThing(); }
在這里要執(zhí)行三個(gè)不同的函數(shù),請(qǐng)注意,無(wú)論是哪個(gè)函數(shù),在執(zhí)行過(guò)程中都不依賴(lài)其他的函數(shù),他們?cè)诒举|(zhì)是相對(duì)獨(dú)立的,只是需要在一個(gè)特定時(shí)間逐一執(zhí)行而已。同樣,你可以使用類(lèi)似chunk()的方法來(lái)執(zhí)行一系列函數(shù),而不會(huì)導(dǎo)致鎖定瀏覽器。
function schedule(functions, context) { setTimeout(function() { var process = functions.shift(); process.call(context); if (functions.length > 0) { setTimeout(arguments.callee, 100); } }, 100); }
schedule函數(shù)有兩個(gè)參數(shù),一個(gè)是包含要執(zhí)行函數(shù)的數(shù)組,另外一個(gè)是標(biāo)明this所屬的上下文對(duì)象。函數(shù)數(shù)組以隊(duì)列方式實(shí)現(xiàn),Timer事件每次觸發(fā)的時(shí)候,都會(huì)將隊(duì)列最前面的函數(shù)取出并執(zhí)行,這個(gè)函數(shù)可以通過(guò)下面的方式執(zhí)行一系列函數(shù):
schedule([doSomething, doSomethingElse, doOneMoreThing], window);
很希望各個(gè)JavaScript的類(lèi)庫(kù)都增加類(lèi)似這樣的進(jìn)程處理函數(shù)。YUI在3.0時(shí)就已經(jīng)引入了Queue對(duì)象,可以通過(guò)timer連續(xù)調(diào)用一組函數(shù)。
無(wú)論現(xiàn)有的技術(shù)可以幫助我們將復(fù)雜的進(jìn)程拆分到什么程度,對(duì)于開(kāi)發(fā)者來(lái)說(shuō),使用這種方法來(lái)理解并確定腳本失控的瓶頸是非常重要的。無(wú)論是太多的循環(huán)、遞歸還是其他的什么,你現(xiàn)在應(yīng)該知道如果處理類(lèi)似的情況。但要記住,這里提到的技術(shù)和函數(shù)只是起到拋磚引玉的作用,在實(shí)際的應(yīng)用中,你應(yīng)該對(duì)它們加以改進(jìn),這樣才能發(fā)揮更大的作用。
本文鏈接:http://www.95time.cn/tech/web/2009/6446.asp
出處:七月佑安
責(zé)任編輯:bluehearts
上一頁(yè) 提升JavaScript運(yùn)行速度之函數(shù)篇 [1] 下一頁(yè)
◎進(jìn)入論壇網(wǎng)頁(yè)制作、WEB標(biāo)準(zhǔn)化版塊參加討論,我還想發(fā)表評(píng)論。
|