index.js 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. function limiter (count) {
  2. var outstanding = 0
  3. var jobs = []
  4. function remove () {
  5. outstanding--
  6. if (outstanding < count) {
  7. dequeue()
  8. }
  9. }
  10. function dequeue () {
  11. var job = jobs.shift()
  12. semaphore.queue = jobs.length
  13. if (job) {
  14. run(job.fn).then(job.resolve).catch(job.reject)
  15. }
  16. }
  17. function queue (fn) {
  18. return new Promise(function (resolve, reject) {
  19. jobs.push({fn: fn, resolve: resolve, reject: reject})
  20. semaphore.queue = jobs.length
  21. })
  22. }
  23. function run (fn) {
  24. outstanding++
  25. try {
  26. return Promise.resolve(fn()).then(function (result) {
  27. remove()
  28. return result
  29. }, function (error) {
  30. remove()
  31. throw error
  32. })
  33. } catch (err) {
  34. remove()
  35. return Promise.reject(err)
  36. }
  37. }
  38. var semaphore = function (fn) {
  39. if (outstanding >= count) {
  40. return queue(fn)
  41. } else {
  42. return run(fn)
  43. }
  44. }
  45. return semaphore
  46. }
  47. function map (items, mapper) {
  48. var failed = false
  49. var limit = this
  50. return Promise.all(items.map(function () {
  51. var args = arguments
  52. return limit(function () {
  53. if (!failed) {
  54. return mapper.apply(undefined, args).catch(function (e) {
  55. failed = true
  56. throw e
  57. })
  58. }
  59. })
  60. }))
  61. }
  62. function addExtras (fn) {
  63. fn.queue = 0
  64. fn.map = map
  65. return fn
  66. }
  67. module.exports = function (count) {
  68. if (count) {
  69. return addExtras(limiter(count))
  70. } else {
  71. return addExtras(function (fn) {
  72. return fn()
  73. })
  74. }
  75. }