1
|
var wrappy = require('wrappy')
|
2
|
var reqs = Object.create(null)
|
3
|
var once = require('once')
|
4
|
|
5
|
module.exports = wrappy(inflight)
|
6
|
|
7
|
function inflight (key, cb) {
|
8
|
if (reqs[key]) {
|
9
|
reqs[key].push(cb)
|
10
|
return null
|
11
|
} else {
|
12
|
reqs[key] = [cb]
|
13
|
return makeres(key)
|
14
|
}
|
15
|
}
|
16
|
|
17
|
function makeres (key) {
|
18
|
return once(function RES () {
|
19
|
var cbs = reqs[key]
|
20
|
var len = cbs.length
|
21
|
var args = slice(arguments)
|
22
|
|
23
|
// XXX It's somewhat ambiguous whether a new callback added in this
|
24
|
// pass should be queued for later execution if something in the
|
25
|
// list of callbacks throws, or if it should just be discarded.
|
26
|
// However, it's such an edge case that it hardly matters, and either
|
27
|
// choice is likely as surprising as the other.
|
28
|
// As it happens, we do go ahead and schedule it for later execution.
|
29
|
try {
|
30
|
for (var i = 0; i < len; i++) {
|
31
|
cbs[i].apply(null, args)
|
32
|
}
|
33
|
} finally {
|
34
|
if (cbs.length > len) {
|
35
|
// added more in the interim.
|
36
|
// de-zalgo, just in case, but don't call again.
|
37
|
cbs.splice(0, len)
|
38
|
process.nextTick(function () {
|
39
|
RES.apply(null, args)
|
40
|
})
|
41
|
} else {
|
42
|
delete reqs[key]
|
43
|
}
|
44
|
}
|
45
|
})
|
46
|
}
|
47
|
|
48
|
function slice (args) {
|
49
|
var length = args.length
|
50
|
var array = []
|
51
|
|
52
|
for (var i = 0; i < length; i++) array[i] = args[i]
|
53
|
return array
|
54
|
}
|