2012-07-25 88 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