83 lines
1.7 KiB
JavaScript
83 lines
1.7 KiB
JavaScript
|
|
||
|
module.exports = function () {
|
||
|
|
||
|
var next = typeof setImmediate === 'undefined' ? setTimeout : setImmediate
|
||
|
|
||
|
var locked = {}
|
||
|
|
||
|
function _releaser (key, exec) {
|
||
|
return function (done) {
|
||
|
return function () {
|
||
|
_release(key, exec)
|
||
|
if (done) done.apply(null, arguments)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function _release (key, exec) {
|
||
|
var i = locked[key].indexOf(exec) //should usually be 0
|
||
|
|
||
|
if(!~i) return
|
||
|
|
||
|
locked[key].splice(i, 1)
|
||
|
|
||
|
//note, that the next locker isn't triggered until next tick,
|
||
|
//so it's always after the released callback
|
||
|
if(isLocked(key))
|
||
|
next(function () {
|
||
|
locked[key][0](_releaser(key, locked[key][0]))
|
||
|
})
|
||
|
else
|
||
|
delete locked[key]
|
||
|
}
|
||
|
|
||
|
function _lock(key, exec) {
|
||
|
if(isLocked(key))
|
||
|
return locked[key].push(exec), false
|
||
|
return locked[key] = [exec], true
|
||
|
}
|
||
|
|
||
|
function lock(key, exec) {
|
||
|
if(Array.isArray(key)) {
|
||
|
var keys = key.length, locks = []
|
||
|
var l = {}
|
||
|
|
||
|
function releaser (done) {
|
||
|
return function () {
|
||
|
var args = [].slice.call(arguments)
|
||
|
for(var key in l)
|
||
|
_release(key, l[key])
|
||
|
done.apply(this, args)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
key.forEach(function (key) {
|
||
|
var n = 0
|
||
|
|
||
|
function ready () {
|
||
|
if(n++) return
|
||
|
if(!--keys)
|
||
|
//all the keys are ready!
|
||
|
exec(releaser)
|
||
|
}
|
||
|
|
||
|
l[key] = ready
|
||
|
if(_lock(key, ready)) ready()
|
||
|
})
|
||
|
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if(_lock(key, exec))
|
||
|
exec(_releaser(key, exec))
|
||
|
}
|
||
|
|
||
|
function isLocked (key) {
|
||
|
return Array.isArray(locked[key]) ? !! locked[key].length : false
|
||
|
}
|
||
|
|
||
|
lock.isLocked = isLocked
|
||
|
|
||
|
return lock
|
||
|
}
|