Skip to content

Instantly share code, notes, and snippets.

@mwmitchell
Created June 9, 2015 14:22
Show Gist options
  • Save mwmitchell/ede020d34aea0b83580d to your computer and use it in GitHub Desktop.
Save mwmitchell/ede020d34aea0b83580d to your computer and use it in GitHub Desktop.
locks.js
function create(){
var observers = {},
locks = {};
var context = {
wait: wait,
owner: owner,
_locks: locks,
_observers: observers
};
/*
locks.wait('foo', 'caller-a', function(lockFn){
// call the lock fn, now other observers will need to "wait"
// until this is released...
var releaseFn = lockFn();
doWork();
console.log(locks.owner('foo'), '===', 'caller-a');
// call the release fn to remove the lock
releaseFn();
})
*/
return context;
function wait(key, owner, handler){
observers[key] = observers[key] || [];
if( ! _.some(observers[key], {owner: owner}) ){
observers[key].push({owner: owner, handler: handler});
execObserverHandlers(key);
return true;
}
}
function owner(key){
return locks[key] && locks[key].owner;
}
function execObserverHandlers(key){
_.each(observers[key], function(observer){
if( ! locks[key] ){
var lockFn = function(){
locks[key] = observer;
return _.partial(doNext, key);
}
// not locked - notify w/a lock function
observer.handler(lockFn);
} else {
// is locked - notify observers but without lock function.
observer.handler(null);
}
// remove the handler so it doesn't get executed again
// If the caller wants continuous access, it can call wait() again
// and get back in line...
_.remove(observers[key], function(v){ return v.owner === observer.owner });
});
}
function doNext(key){
var currentOwner = owner(key);
if( currentOwner ){
delete locks[key];
if( observers[key].length === 0 ){
delete observers[key];
}
execObserverHandlers(key);
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment