inflight.js
 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  }