组合_.memoize和_.throttle来限制函数调用并在时间窗口内缓存结果?

时间:2014-05-23 11:12:22

标签: javascript caching underscore.js

使用一个函数调用一系列调用来返回一个结果,该结果在Angular模板中一次多次请求。在这些请求期间,结果不会改变,因此在函数内部进行额外调用的开销是不必要的。

是否可以在一定的等待时间内创建一个缓存并返回相同结果的限制函数?

与下面的简化示例一致。

var throttleCache = _.memoizeThrottle(function() {
    return _.now();
}, 100);

_.delay(throttleCache, 0); // now + 0ms
_.delay(throttleCache, 10); // now + 0ms
_.delay(throttleCache, 99); // now + 0ms
_.delay(throttleCache, 101); // now + 101ms
_.delay(throttleCache, 150); // now + 101ms

据我所知,_.memoize根据参数无限期地缓存结果,无法定时自动刷新此缓存。并且_.throttle_.debounce仅在集合约束内触发函数,但不返回包含函数的输出。

3 个答案:

答案 0 :(得分:2)

我使用_.memoize方法扩展它并添加一个ttl参数,以强制在过期时重新计算值。

#!/usr/bin/env coffee

_=require 'underscore'

# Memoize an expensive function by storing its results.
# After ttl time, the value will be recomputed

memoinesic = (func, hasher=_.identity, ttl=0)->

    memoize = ()->

        cache = memoize.cache
        key = hasher.apply(@,arguments)
        now = Date.now()

        if !_.has(cache,key) or now>cache[key].expires

            cache[key] = 
                value: func.apply(@,arguments)
                expires: now+ttl

        cache[key].value

    memoize.cache = {}

    memoize

_.mixin(memoinesic:memoinesic)

# Let's try it!

appendToNow = _.memoinesic(
    (x)-> "#{x}:#{Date.now()}",
    null,
    1000
)

logTimedFoo = _.compose console.log,_.partial appendToNow,'foo'

logTimedFoo()

setInterval logTimedFoo,200

答案 1 :(得分:0)

根据underscorejs source,看起来_.throttle和_.debounce都会返回上次计算的结果。就这样,他们已经做了你想做的事。

答案 2 :(得分:0)

memoize不会过期,并且不管参数如何,throttled都会返回相同的值。

这是节流和memoize的组合,以获得一个记忆版本的功能,该功能将在固定的持续时间后重新计算。

// tester to get a combinaison of throttle and memoize.

var _ = require('lodash');

var start = Date.now();

var func = function(text) {
  var toDisplay = "argument " + text + " at " + (Date.now() - start);
  console.log("executed with", toDisplay);
  return toDisplay;
};

var getCachedFunc = function(myFuncToCache, cacheDuration, context) {
  // we need to return a different throttled function for each different parameters so memoize it
  var memoizedFunction = _.memoize(function() {
    var myFuncToCacheArguments = arguments;
    var throttledFunc = _.throttle(myFuncToCache, cacheDuration, {trailing: false});
    return function executeThrottledFunction() {return throttledFunc.apply(null, myFuncToCacheArguments);};
  });

  return function applyMemoizedFunction() {
    // apply the throttled function
    return memoizedFunction.apply(context, arguments)();
  };
};

var myCachedFunc = getCachedFunc(func, 4000);

var callWithArgument1 = function() {
  console.log("calling with argument 1 at " + (Date.now() - start));
  console.log("returned",myCachedFunc('1'));
};

var callWithArgument2 = function() {
  console.log("calling with argument 2 at " + (Date.now() - start));
  console.log("returned",myCachedFunc('2'));
};

callWithArgument1();
setTimeout(function() {callWithArgument1();}, 2000);
setTimeout(function() {callWithArgument2();}, 2200);
setTimeout(function() {callWithArgument1();}, 5000);

http://jsfiddle.net/6kq4rt0b/