Semaphore.js 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  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. /** @type {number} */
  19. this.available = available;
  20. /** @type {(() => void)[]} */
  21. this.waiters = [];
  22. /** @private */
  23. this._continue = this._continue.bind(this);
  24. }
  25. /**
  26. * Acquires a permit for the callback immediately when one is available or
  27. * queues the callback until another task releases its permit.
  28. * @param {() => void} callback function block to capture and run
  29. * @returns {void}
  30. */
  31. acquire(callback) {
  32. if (this.available > 0) {
  33. this.available--;
  34. callback();
  35. } else {
  36. this.waiters.push(callback);
  37. }
  38. }
  39. /**
  40. * Releases a permit and schedules the next waiting callback, if any.
  41. */
  42. release() {
  43. this.available++;
  44. if (this.waiters.length > 0) {
  45. process.nextTick(this._continue);
  46. }
  47. }
  48. /**
  49. * Drains the next waiting callback after a permit becomes available.
  50. */
  51. _continue() {
  52. if (this.available > 0 && this.waiters.length > 0) {
  53. this.available--;
  54. const callback = /** @type {(() => void)} */ (this.waiters.pop());
  55. callback();
  56. }
  57. }
  58. }
  59. module.exports = Semaphore;