Skip to content

Instantly share code, notes, and snippets.

@donabrams
Created February 1, 2011 19:28
Show Gist options
  • Save donabrams/806462 to your computer and use it in GitHub Desktop.
Save donabrams/806462 to your computer and use it in GitHub Desktop.
Simple js caching with queuing
//
// This is a cache implemenation
// You can synchronously put(), contains() and markAsLoading().
// You can asynchronously get() and getput() and putget().
//
// get() is asynchronous because it might wait until a put() is called if
// the key is marked as loading.
// key is whatever you want it to be, required.
// callback is an optional function that takes 2 arguments:
// success/boolean and the value/?
// maxWait is optional, max wait time in ms
//
// putget() and getput() act both a get and a put. If the key is ready or
// markedAsLoading, it acts just like get(). Otherwise, it marks the key
// as loading, loads a value and gets it. If loader is not a function,
// it calls put(key,loader) and then get(key,callback). If loader is a
// function, it passes loader() a callback function that takes a value,
// calls put(key,value) then get(key,callback).
//
var cache = function(args) {
this.cache={};
this.ready={};
this.waiters={};
this.allowWaiting = true;
this.contains = function(key) {
return this.ready[key] !== undefined;
};
this.markAsLoading = function(key) {
this.ready = false;
}
// key is whatever you want it to be
// callback takes 2 arguments: success and the object
// maxWait in ms, optional
this.get = function(key, callback, maxWait) {
if (callback == null) {
return;
}
if (this.ready[key] === undefined) {
callback(false);
} else if (this.ready[key]) {
callback(true, this.cache[key]);
} else if (this.allowWaiting) {
this._addWaiter(key, callback, maxWait);
}
};
this.put = function(key, value) {
this.cache[key] = value;
this.ready[key] = true;
if (this.allowWaiting) {
this._resumeWaiters(key,value);
}
};
this.putget = this.getput = function(key, loader, callback, maxWait) {
if (this.ready[key] === undefined) {
this.markAsLoading(key);
if ($.isFunction(loader)) {
if (maxWait) {
this.get(key, callback, maxWait);
}
var that = this;
loader(function(value) {
that.put(key, value);
if (!maxWait) {
that.get(key, callback);
}
});
} else {
this.put(key, loader);
this.get(key, callback);
}
} else {
this.get(key, callback);
}
};
this._addWaiter = function(key, callback, maxWait) {
var waits = this.waiters[key] = this.waiters[key] || [];
var i = waits.push(callback);
if (maxWait) {
var remove = function() {
if (waits[i] != null) {
var callback = waits[i];
waits[i] = null;
callback(false);
}
};
setTimeout(remove, maxWait);
}
};
this._resumeWaiters = function(key,value) {
var waits = this.waiters[key];
$.each(waits, function(i) {
var callback = waits[i];
if (callback != null) {
waits[i] = null;
callback(true, value);
}
});
};
$.extend(true, this, args);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment