promisen.js
function memoize(task, expire, hasher) {
    var memo = memoizeTask.memo = {};
    expire -= 0;
    var timers = {};
    if (!hasher) hasher = JSON.stringify.bind(JSON);
    return memoizeTask;

    function memoizeTask(value) {
      return waterfall([hasher, readCache]).call(this, value);

      // read previous result from cache
      function readCache(hash) {
        if (hash in memo) return memo[hash];
        return waterfall([task, writeCache]).call(this, value);

        // write new result to cache
        function writeCache(result) {
          result = memo[hash] = resolve(result);
          if (expire) {
            // cancel previous timer
            if (timers[hash]) clearTimeout(timers[hash]);
            // add new timer
            timers[hash] = setTimeout(clearCache, expire);
          }
          return result;
        }

        // clear expired result
        function clearCache() {
          delete memo[hash];
          delete timers[hash];
        }
      }
    }
  }
function memoize(task, expire, hasher) {
    var memo = memoizeTask.memo = {};
    expire -= 0;
    var timers = {};
    if (!hasher) hasher = JSON.stringify.bind(JSON);
    return memoizeTask;

    function memoizeTask(value) {
      return waterfall([hasher, readCache]).call(this, value);

      // read previous result from cache
      function readCache(hash) {
        if (hash in memo) return memo[hash];
        return waterfall([task, writeCache]).call(this, value);

        // write new result to cache
        function writeCache(result) {
          result = memo[hash] = resolve(result);
          if (expire) {
            // cancel previous timer
            if (timers[hash]) clearTimeout(timers[hash]);
            // add new timer
            timers[hash] = setTimeout(clearCache, expire);
          }
          return result;
        }

        // clear expired result
        function clearCache() {
          delete memo[hash];
          delete timers[hash];
        }
      }
    }
  }
function memoize ( task , expire , hasher ) { var memo = memoizeTask . memo = { } ; expire -= 0 ; var timers = { } ; if ( ! hasher ) hasher = JSON . stringify . bind ( JSON ) ; return memoizeTask ; function memoizeTask ( value ) { return waterfall ( [ hasher , readCache ] ) . call ( this , value ) ; // read previous result from cache function readCache ( hash ) { if ( hash in memo ) return memo [ hash ] ; return waterfall ( [ task , writeCache ] ) . call ( this , value ) ; // write new result to cache function writeCache ( result ) { result = memo [ hash ] = resolve ( result ) ; if ( expire ) { // cancel previous timer if ( timers [ hash ] ) clearTimeout ( timers [ hash ] ) ; // add new timer timers [ hash ] = setTimeout ( clearCache , expire ) ; } return result ; } // clear expired result function clearCache ( ) { delete memo [ hash ] ; delete timers [ hash ] ; } } } }
creates a promise-returning function which caches a result of task.

The cache of result is exposed as the memo property of the function returned by memoize.

@class promisen
@static
@function memoize
@param task {Function} task to wrap
@param expire {Number} millisecond until cache expired
@param [hasher] {Function} default: JSON.stringify()
@returns {Function} promise-returning function
@example
var promisen = require("promisen");
var request = require("request");

var ajaxGet = promisen.denodeify(request);
var cachedAjax = promisen.memoize(ajaxGet);

var req = {url: "http://www.example.com/"};
cachedAjax(req).then(function(res) {...}); // res.body contains response body
creates a promise - returning function which caches a result of task .