enumerator.js 2.6 KB

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