UNPKG

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