enumerator.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import {
  2. isArray,
  3. isMaybeThenable
  4. } from './utils';
  5. import {
  6. noop,
  7. reject,
  8. fulfill,
  9. subscribe,
  10. FULFILLED,
  11. REJECTED,
  12. PENDING,
  13. handleMaybeThenable
  14. } from './-internal';
  15. import then from './then';
  16. import Promise from './promise';
  17. import originalResolve from './promise/resolve';
  18. import originalThen from './then';
  19. import { makePromise, PROMISE_ID } from './-internal';
  20. function validationError() {
  21. return new Error('Array Methods must be provided an Array');
  22. };
  23. export default class Enumerator {
  24. constructor(Constructor, input) {
  25. this._instanceConstructor = Constructor;
  26. this.promise = new Constructor(noop);
  27. if (!this.promise[PROMISE_ID]) {
  28. makePromise(this.promise);
  29. }
  30. if (isArray(input)) {
  31. this.length = input.length;
  32. this._remaining = input.length;
  33. this._result = new Array(this.length);
  34. if (this.length === 0) {
  35. fulfill(this.promise, this._result);
  36. } else {
  37. this.length = this.length || 0;
  38. this._enumerate(input);
  39. if (this._remaining === 0) {
  40. fulfill(this.promise, this._result);
  41. }
  42. }
  43. } else {
  44. reject(this.promise, validationError());
  45. }
  46. }
  47. _enumerate(input) {
  48. for (let i = 0; this._state === PENDING && i < input.length; i++) {
  49. this._eachEntry(input[i], i);
  50. }
  51. }
  52. _eachEntry(entry, i) {
  53. let c = this._instanceConstructor;
  54. let { resolve } = c;
  55. if (resolve === originalResolve) {
  56. let then;
  57. let error;
  58. let didError = false;
  59. try {
  60. then = entry.then;
  61. } catch (e) {
  62. didError = true;
  63. error = e;
  64. }
  65. if (then === originalThen &&
  66. entry._state !== PENDING) {
  67. this._settledAt(entry._state, i, entry._result);
  68. } else if (typeof then !== 'function') {
  69. this._remaining--;
  70. this._result[i] = entry;
  71. } else if (c === Promise) {
  72. let promise = new c(noop);
  73. if (didError) {
  74. reject(promise, error);
  75. } else {
  76. handleMaybeThenable(promise, entry, then);
  77. }
  78. this._willSettleAt(promise, i);
  79. } else {
  80. this._willSettleAt(new c(resolve => resolve(entry)), i);
  81. }
  82. } else {
  83. this._willSettleAt(resolve(entry), i);
  84. }
  85. }
  86. _settledAt(state, i, value) {
  87. let { promise } = this;
  88. if (promise._state === PENDING) {
  89. this._remaining--;
  90. if (state === REJECTED) {
  91. reject(promise, value);
  92. } else {
  93. this._result[i] = value;
  94. }
  95. }
  96. if (this._remaining === 0) {
  97. fulfill(promise, this._result);
  98. }
  99. }
  100. _willSettleAt(promise, i) {
  101. let enumerator = this;
  102. subscribe(
  103. promise, undefined,
  104. value => enumerator._settledAt(FULFILLED, i, value),
  105. reason => enumerator._settledAt(REJECTED, i, reason)
  106. );
  107. }
  108. };