Semaphore.js 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. /**
  7. * Simple counting semaphore used to limit how many asynchronous tasks may run
  8. * concurrently.
  9. */
  10. class Semaphore {
  11. /**
  12. * Initializes the semaphore with the number of permits that may be held at
  13. * the same time.
  14. * @param {number} available the amount available number of "tasks"
  15. * in the Semaphore
  16. */
  17. constructor(available) {
  18. this.available = available;
  19. /** @type {(() => void)[]} */
  20. this.waiters = [];
  21. /** @private */
  22. this._continue = this._continue.bind(this);
  23. }
  24. /**
  25. * Acquires a permit for the callback immediately when one is available or
  26. * queues the callback until another task releases its permit.
  27. * @param {() => void} callback function block to capture and run
  28. * @returns {void}
  29. */
  30. acquire(callback) {
  31. if (this.available > 0) {
  32. this.available--;
  33. callback();
  34. } else {
  35. this.waiters.push(callback);
  36. }
  37. }
  38. /**
  39. * Releases a permit and schedules the next waiting callback, if any.
  40. */
  41. release() {
  42. this.available++;
  43. if (this.waiters.length > 0) {
  44. process.nextTick(this._continue);
  45. }
  46. }
  47. /**
  48. * Drains the next waiting callback after a permit becomes available.
  49. */
  50. _continue() {
  51. if (this.available > 0 && this.waiters.length > 0) {
  52. this.available--;
  53. const callback = /** @type {(() => void)} */ (this.waiters.pop());
  54. callback();
  55. }
  56. }
  57. }
  58. module.exports = Semaphore;