Source: tools/Defer.js

  1. require('../../docs');
  2. /**
  3. * A function that creates an awaitable timout.
  4. *
  5. * @param {Number} ms Milliseconds to wait before resolving
  6. * @returns {Promise<void>} a Promise that is resolved after
  7. * the amount of milliseconds given.
  8. */
  9. const timeout = ms => new Promise((resolve, reject) => {
  10. setTimeout(resolve, ms);
  11. });
  12. /**
  13. * @template T
  14. *
  15. * Creates a deferred Promise and returns an object with functions
  16. * that can be used to resolve or reject the deferred.
  17. *
  18. * @returns {Deferred<T>}
  19. */
  20. const defer = () => {
  21. /** @type {DeferredClass<T>} */
  22. return new DeferredClass();
  23. };
  24. /**
  25. * @template T
  26. */
  27. class DeferredClass {
  28. constructor() {
  29. /** @private */
  30. this._resolve = null;
  31. /** @private */
  32. this._reject = null;
  33. const that = this;
  34. /** @private */
  35. this._promise = new Promise((resolve, reject) => {
  36. that._resolve = resolve;
  37. that._reject = reject;
  38. });
  39. /** @private */
  40. this._isResolved = false;
  41. /** @private */
  42. this._isRejected = false;
  43. };
  44. /**
  45. * @type {Boolean}
  46. */
  47. get isResolved() {
  48. return this._isResolved;
  49. };
  50. /**
  51. * @type {Boolean}
  52. */
  53. get isRejected() {
  54. return this._isRejected;
  55. };
  56. /**
  57. * @type {Promise<T>}
  58. */
  59. get promise() {
  60. return this._promise;
  61. };
  62. /**
  63. * @param {T} useValue
  64. * @returns {this}
  65. */
  66. resolve(useValue) {
  67. if (this.isResolved) {
  68. throw new Error('Already resolved');
  69. }
  70. if (this.isRejected) {
  71. throw new Error('Already rejected');
  72. }
  73. this._isResolved = true;
  74. this._resolve(useValue);
  75. return this;
  76. };
  77. /**
  78. * @param {any} [error]
  79. * @returns {this}
  80. */
  81. reject(error) {
  82. if (this.isRejected) {
  83. throw new Error('Already rejected')
  84. }
  85. if (this.isResolved) {
  86. throw new Error('Already resolved');
  87. }
  88. this._isRejected = true;
  89. this._reject(...arguments);
  90. return this;
  91. };
  92. };
  93. /**
  94. * Mocha does not support this use case (async function with done):
  95. * https://github.com/mochajs/mocha/issues/2407#issuecomment-237408877
  96. * This function creates a deferred that can be resolved/rejected using
  97. * a generic done-callback.
  98. *
  99. * @returns {[Promise<any>, callbackHandler<any>]} an array where
  100. * the first element is the promise that can be returned to mocha's test
  101. * runner and the second element is the done-function, which, when called
  102. * with no arguments, resolves the promise. Otherwise, it will reject the
  103. * promise.
  104. */
  105. const deferMocha = () => {
  106. const deferred = defer();
  107. return [deferred.promise, error => {
  108. if (error === void 0) {
  109. deferred.resolve();
  110. } else {
  111. deferred.reject(error);
  112. }
  113. }];
  114. };
  115. module.exports = Object.freeze({
  116. timeout,
  117. defer,
  118. deferMocha,
  119. DeferredClass
  120. });