2012-07-25 122 views
2

在Javascript中,有沒有辦法緩存結果的功能是:緩存結果的功能?

  • a)。計算昂貴。
  • b)。多次調用。

舉例來說,一個經常被調用的遞歸因子函數。通常我會創建一個單獨的數組,例如facotrialResults = [];,並在計算它們時將其結果添加到它們,factorialResults[x] = result;但是,是否有更好的方法可以在不使用向全局名稱空間中添加新變量的情況下完成此緩存?

回答

1

您可以定義自己的功能屬性,以便緩存結果與功能相關聯的,而不是在一個新的數組填充全局命名空間:

function factorial(n) { 
    if (n > 0) { 
    if (!(n in factorial)) // Check if we already have the result cached. 
     factorial[n] = n * factorial(n-1); 
    return factorial[n]; 
    } 
    return NaN; 
} 
factorial[1] = 1; // Cache the base case. 

與此唯一的問題是檢查的開銷如果結果已被緩存。但是,如果檢查的複雜程度遠低於重新計算問題的複雜程度,那麼它非常值得。

+0

它破壞自己的功能我想緩存功能必須包裝自己的功能更好。 – blueiur 2012-07-26 00:00:47

2

您可以考慮將underscore庫滾動到您的環境中。它對許多事情很有用,包括它的功能memoize功能

通過緩存計算結果來記憶給定函數。有用的 加速慢運行計算。如果傳遞了一個可選的 散列函數,它將被用於根據原始函數的參數來計算散列鍵,以存儲結果 。默認的 hashFunction只是使用memoized函數的第一個參數作爲密鑰 。

var fibonacci = _.memoize(function(n) { 
    return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2); 
}); 
3

你可以散列連接到要緩存的功能。

var expensive_fn = function(val) { 
    var result = arguments.callee.cache[val]; 
    if(result == null || result == undefined) { 
    //do the work and set result=... 
    arguments.callee.cache[val]=result; 
    } 
    return result; 
} 
expensive_fn.cache = {}; 

這將要求功能是1-1功能,沒有副作用。

+0

.callee不推薦使用ecma5並破壞自己的功能 – blueiur 2012-07-26 00:01:57

+0

然後您可以明確地引用該函數。 – matsko 2012-07-27 00:11:46

0

使用緩存

這是通用的解決方案

// wrap cache function 
var wrapCache = function(f, fKey){ 
    fKey = fKey || function(id){ return id; }; 
    var cache = {}; 

    return function(key){ 
     var _key = fKey(key); 
     if (!cache[_key]){ 
      cache[_key] = f(key); 
     }; 

     return cache[_key]; 
    }; 
}; 

// functions that expensive 
var getComputedRGB = function(n){ 
    console.log("getComputedRGB called", n) ; 
    return n * n * n; 
}; 

// wrapping expensive 
var getComputedRGBCache = wrapCache(getComputedRGB, JSON.stringify); 


console.log("normal call"); 
console.log(getComputedRGB(10)); 
console.log(getComputedRGB(10)); 
console.log(getComputedRGB(10)); 
console.log(getComputedRGB(10)); 
// compute 4 times 


console.log("cached call") ; 
console.log(getComputedRGBCache(10)); 
console.log(getComputedRGBCache(10)); 
console.log(getComputedRGBCache(10)); 
console.log(getComputedRGBCache(10)); 
// compute just 1 times 


// output 
=> normal call 
getComputedRGB called 10 
1000 
getComputedRGB called 10 
1000 
getComputedRGB called 10 
1000 
getComputedRGB called 10 
1000 

=> cached call 
getComputedRGB called 10 
1000 
1000 
1000 
1000