(function (root, factory) {
    if (typeof exports === 'object') {
        module.exports = factory(require('lru-cache'));
    } else if (typeof define === 'function' && define.amd) {
        define(['LRUCache'], factory);
    } else {
        root.memoizeAsync = factory(root.LRUCache);
    }
}(this, function (LRU) {
    var defer;
    if (typeof setImmediate === 'function') {
        // Node 0.10+
        defer = setImmediate;
    } else if (typeof process === 'object' && process && process.nextTick) {
        defer = process.nextTick;
    } else {
        // Browser
        defer = function (fn) {
            setTimeout(fn, 0);
        };
    }

    var nextCacheKeyPrefix = 1;
    return function memoizeAsync(lambda, options) {
        options = options || {};
        var argumentsStringifier = options.argumentsStringifier || function (args) {
                return args.map(String).join('\x1d'); // Group separator
            },
            waitingCallbacksByStringifiedArguments = {},
            cacheKeyPrefix,
            cache;

        if ('cacheKeyPrefix' in options) {
            cacheKeyPrefix = String(options.cacheKeyPrefix);
        } else {
            cacheKeyPrefix = nextCacheKeyPrefix + '\x1d';
            nextCacheKeyPrefix += 1;
        }

        if (options.cache) {
            cache = options.cache;
        } else {
            var lruCacheOptions = {};
            for (var propertyName in options) {
                if (Object.prototype.hasOwnProperty.call(options, propertyName)) {
                    var value = options[propertyName];
                    if (propertyName === 'length') {
                        // Make sure that the 'length' function gets called with the resultCallbackParams as actual parameters
                        // so it matches the signature of the callback:
                        lruCacheOptions.length = function (resultCallbackParams) {
                            return options.length.apply(this, resultCallbackParams);
                        };
                    } else if (propertyName !== 'argumentsStringifier' && propertyName !== 'cacheKeyPrefix') {
                        lruCacheOptions[propertyName] = value;
                    }
                }
            }
            cache = new LRU(lruCacheOptions);
        }

        function memoizer() { // ...
            var that = this, // In case you want to create a memoized method
                args = Array.prototype.slice.call(arguments),
                cb = args.pop(),
                stringifiedArguments = String(argumentsStringifier(args)), // In case the function returns a non-string
                resultCallbackParams = cache.get(cacheKeyPrefix + stringifiedArguments),
                updateCache = false;

            if (typeof resultCallbackParams !== 'undefined') {
                if (getAge.apply(null, args) > options.refreshAge && !waitingCallbacksByStringifiedArguments[stringifiedArguments]) {
                    waitingCallbacksByStringifiedArguments[stringifiedArguments] = [function () {}];
                    updateCache = true;
                }
                defer(function () {
                    cb.apply(that, resultCallbackParams);
                });
            } else if (waitingCallbacksByStringifiedArguments[stringifiedArguments]) {
                waitingCallbacksByStringifiedArguments[stringifiedArguments].push(cb);
            } else {
                waitingCallbacksByStringifiedArguments[stringifiedArguments] = [cb];
                updateCache = true;
            }

            if (updateCache) {
                lambda.apply(options.context || that, args.concat(function () { // ...
                    var resultCallbackParams = Array.prototype.slice.call(arguments),
                        waitingCallbacks = waitingCallbacksByStringifiedArguments[stringifiedArguments];
                    if (!resultCallbackParams[0] || options.errors) {
                        cache.set(cacheKeyPrefix + stringifiedArguments, resultCallbackParams);
                    }
                    delete waitingCallbacksByStringifiedArguments[stringifiedArguments];
                    // Wait another tick in case an ill-behaved lambda called its callback immediately:
                    defer(function () {
                        waitingCallbacks.forEach(function (cb) {
                            cb.apply(that, resultCallbackParams);
                        });
                    });
                }));
            }
        }

        memoizer.cache = cache;
        memoizer.cacheKeyPrefix = cacheKeyPrefix;
        memoizer.argumentsStringifier = argumentsStringifier;

        memoizer.peek = function () { // ...
            return cache.peek(cacheKeyPrefix + argumentsStringifier(Array.prototype.slice.call(arguments)));
        };

        memoizer.getTtl = function () {
            var entry = cache._cache[cacheKeyPrefix + argumentsStringifier(Array.prototype.slice.call(arguments))];
            if (!entry) {
                return -1;
            }
            return Math.max(-1, entry.now - Date.now() + cache._maxAge);
        };

        var getAge = memoizer.getAge = function () {
            var entry = cache._cache[cacheKeyPrefix + argumentsStringifier(Array.prototype.slice.call(arguments))];
            if (!entry) {
                return -1;
            }
            if (entry.now === 0) {
                // node-lru doesn't bother maintaining entry.now when there's no maxAge specified.
                return;
            }
            return Date.now() - entry.now;
        };

        memoizer.purge = function () { // ...
            cache.del(cacheKeyPrefix + argumentsStringifier(Array.prototype.slice.call(arguments)));
        };

        memoizer.purgeAll = function () {
            // Cannot use cache.forEach with cache.del in the callback, that screws up the iteration.
            var keys = cache.keys();
            for (var i = 0 ; i < keys.length ; i += 1) {
                var key = keys[i];
                if (key.indexOf(cacheKeyPrefix) === 0) {
                    cache.del(key);
                }
            }
        };

        return memoizer;
    };
}));

@@ -2965,109 +2965,8 @@
 ) %7B%0A
-                    waitingCallbacksByStringifiedArguments%5BstringifiedArguments%5D = %5Bfunction () %7B%7D%5D;%0A
     
@@ -3953,32 +3953,80 @@
               %7D%0A
+                    if (waitingCallbacks) %7B%0A    
                 
@@ -4118,16 +4118,20 @@
         
+    
 // Wait 
@@ -4218,32 +4218,36 @@
                 
+    
 defer(function (
@@ -4242,32 +4242,36 @@
 r(function () %7B%0A
+    
                 
@@ -4339,32 +4339,36 @@
                 
+    
 cb.apply(that, r
@@ -4381,32 +4381,64 @@
 allbackParams);%0A
+                            %7D);%0A
                 
@@ -4441,32 +4441,32 @@
             %7D);%0A
+
                 
@@ -4462,34 +4462,32 @@
                %7D
-);
 %0A               

Improve the handling of the "refresh" case where there are no waiting callbacks.