提升JavaScript效率之遞歸優(yōu)化:Memoization

遞歸是拖慢腳本運(yùn)行速度的大敵之一。太多的遞歸會(huì)讓瀏覽器變得越來越慢直到死掉或者莫名其妙的突然自動(dòng)退出。
我們可以使用memoization技術(shù)來替代函數(shù)中太多的遞歸調(diào)用,通過封裝一個(gè)Memoization函數(shù)去緩存之前運(yùn)算結(jié)果,從而能避免無謂的運(yùn)算避免重復(fù)工作,將執(zhí)行過的運(yùn)算或操作,緩存起來,如果后續(xù)有相同的操作可直接從緩存中查找,沒有則進(jìn)行遞歸,可大大減少遞歸的工作量,提高性能。

一、簡(jiǎn)單實(shí)現(xiàn)

通過 Memoization 的定義和原理,我們就可以初步實(shí)現(xiàn) Memoization

function memoizer(fundamental, cache){
    cache = cache || {}
    var shell = function(arg){
        if (! (arg in cache)){
            cache[arg] = fundamental(shell, arg)
        }
        return cache[arg];
    };
    return shell;
}

函數(shù)緩存其實(shí)就是利用閉包,將函數(shù)參數(shù)作為存儲(chǔ)對(duì)象的鍵(key),函數(shù)結(jié)果作為存儲(chǔ)對(duì)象的 value 值。原有函數(shù)被設(shè)置為第一個(gè)參數(shù),第二個(gè)參數(shù)是緩存對(duì)象,為可選參數(shù),因?yàn)椴⒉皇撬械倪f歸函數(shù)都包含初始信息。在函數(shù)內(nèi)部,使用一個(gè)對(duì)象來緩存函數(shù)值,在shell函數(shù)里,我使用了in操作符來判斷參數(shù)是否已經(jīng)包含在緩存里。這種寫法比測(cè)試類型不是undefined更加安全,因?yàn)閡ndefined是一個(gè)有效的返回值。

二、使用場(chǎng)景 計(jì)算斐波那契數(shù)列

斐波那契數(shù)列的特點(diǎn)是后一個(gè)數(shù)等于前面兩個(gè)數(shù)的和
指的是這樣一個(gè)數(shù)列:1、1、2、3、5、8、13、21、34、……在數(shù)學(xué)上,斐波那契數(shù)列以如下被以遞推的方法定義:F(0)=0,F(xiàn)(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)

var count = 0;
var fibonacci = function(n) {
  count++;
  return n < 2 ? n : fibonacci(n - 2) + fibonacci(n - 1);
}
fibonacci(40)
// 102334155
console.log(count);  
//331,160,280 !!!  由于每有緩存結(jié)果,每次都需要進(jìn)行函數(shù)調(diào)用

這里可以看到 在使用遞歸函數(shù)計(jì)算的時(shí)候,沒有做結(jié)果緩存,每次計(jì)算都要重新調(diào)用函數(shù)計(jì)算。那我們就犧牲一小部分內(nèi)存,用來緩存每次計(jì)算的值,就可以減少函數(shù)的調(diào)用

var count = 0
fibonacci =
    memoizer(function (recur, n) {
        count++
       return recur(n - 1) + recur(n - 2);
    }, {"0":0, "1":1});
fibonacci(40)
console.log(count);  
// 39  可以看到最后通過 memoize 函數(shù)記憶,使得函數(shù)執(zhí)行次數(shù)只需要39次,大大優(yōu)化了函數(shù)執(zhí)行計(jì)算的性能消耗,

三、總結(jié)

函數(shù)記憶(memoization)將函數(shù)的參數(shù)和結(jié)果值,保存在對(duì)象當(dāng)中,用一部分的內(nèi)存開銷來提高程序計(jì)算的性能,常用在遞歸和重復(fù)運(yùn)算較多的場(chǎng)景中,對(duì)于那些有著嚴(yán)格定義的結(jié)果集的遞歸算法來說,提升運(yùn)行效果比較顯著。
參考文獻(xiàn)
https://humanwhocodes.com/blog/2009/01/20/speed-up-your-javascript-part-2/
https://humanwhocodes.com/blog/2009/01/20/speed-up-your-javascript-part-3/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容