async-fifo-queue.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. /**
  2. * (c) 2017-2025 BullForce Labs AB, MIT Licensed.
  3. * @see LICENSE.md
  4. *
  5. */
  6. class Node {
  7. constructor(value) {
  8. this.value = undefined;
  9. this.next = null;
  10. this.value = value;
  11. }
  12. }
  13. class LinkedList {
  14. constructor() {
  15. this.length = 0;
  16. this.head = null;
  17. this.tail = null;
  18. }
  19. push(value) {
  20. const newNode = new Node(value);
  21. if (!this.length) {
  22. this.head = newNode;
  23. }
  24. else {
  25. this.tail.next = newNode;
  26. }
  27. this.tail = newNode;
  28. this.length += 1;
  29. return newNode;
  30. }
  31. shift() {
  32. if (!this.length) {
  33. return null;
  34. }
  35. else {
  36. const head = this.head;
  37. this.head = this.head.next;
  38. this.length -= 1;
  39. return head;
  40. }
  41. }
  42. }
  43. /**
  44. * AsyncFifoQueue
  45. *
  46. * A minimal FIFO queue for asynchronous operations. Allows adding asynchronous operations
  47. * and consume them in the order they are resolved.
  48. */
  49. export class AsyncFifoQueue {
  50. constructor(ignoreErrors = false) {
  51. this.ignoreErrors = ignoreErrors;
  52. /**
  53. * A queue of completed promises. As the pending
  54. * promises are resolved, they are added to this queue.
  55. */
  56. this.queue = new LinkedList();
  57. /**
  58. * A set of pending promises.
  59. */
  60. this.pending = new Set();
  61. this.newPromise();
  62. }
  63. add(promise) {
  64. this.pending.add(promise);
  65. promise
  66. .then(data => {
  67. this.pending.delete(promise);
  68. if (this.queue.length === 0) {
  69. this.resolvePromise(data);
  70. }
  71. this.queue.push(data);
  72. })
  73. .catch(err => {
  74. // Ignore errors
  75. if (this.ignoreErrors) {
  76. this.queue.push(undefined);
  77. }
  78. this.pending.delete(promise);
  79. this.rejectPromise(err);
  80. });
  81. }
  82. async waitAll() {
  83. await Promise.all(this.pending);
  84. }
  85. numTotal() {
  86. return this.pending.size + this.queue.length;
  87. }
  88. numPending() {
  89. return this.pending.size;
  90. }
  91. numQueued() {
  92. return this.queue.length;
  93. }
  94. resolvePromise(data) {
  95. this.resolve(data);
  96. this.newPromise();
  97. }
  98. rejectPromise(err) {
  99. this.reject(err);
  100. this.newPromise();
  101. }
  102. newPromise() {
  103. this.nextPromise = new Promise((resolve, reject) => {
  104. this.resolve = resolve;
  105. this.reject = reject;
  106. });
  107. }
  108. async wait() {
  109. return this.nextPromise;
  110. }
  111. async fetch() {
  112. var _a;
  113. if (this.pending.size === 0 && this.queue.length === 0) {
  114. return;
  115. }
  116. while (this.queue.length === 0) {
  117. try {
  118. await this.wait();
  119. }
  120. catch (err) {
  121. // Ignore errors
  122. if (!this.ignoreErrors) {
  123. console.error('Unexpected Error in AsyncFifoQueue', err);
  124. }
  125. }
  126. }
  127. return (_a = this.queue.shift()) === null || _a === void 0 ? void 0 : _a.value;
  128. }
  129. }
  130. //# sourceMappingURL=async-fifo-queue.js.map