import { isArray, isMaybeThenable } from './utils'; import { noop, resolve, handleMaybeThenable, reject, fulfill, subscribe, FULFILLED, REJECTED, PENDING, getThen } from './-internal'; import Promise from './promise'; import originalThen from './then'; import originalResolve from './promise/resolve'; export default class Enumerator { constructor(Constructor, input, abortOnReject, label) { this._instanceConstructor = Constructor; this.promise = new Constructor(noop, label); this._abortOnReject = abortOnReject; this._init(...arguments); } _init(Constructor, input) { let len = input.length || 0; this.length = len; this._remaining = len; this._result = new Array(len); this._enumerate(input); if (this._remaining === 0) { fulfill(this.promise, this._result); } } _enumerate(input) { let length = this.length; let promise = this.promise; for (let i = 0; promise._state === PENDING && i < length; i++) { this._eachEntry(input[i], i); } } _settleMaybeThenable(entry, i) { let c = this._instanceConstructor; let resolve = c.resolve; if (resolve === originalResolve) { let then = getThen(entry); if (then === originalThen && entry._state !== PENDING) { entry._onError = null; this._settledAt(entry._state, i, entry._result); } else if (typeof then !== 'function') { this._remaining--; this._result[i] = this._makeResult(FULFILLED, i, entry); } else if (c === Promise) { let promise = new c(noop); handleMaybeThenable(promise, entry, then); this._willSettleAt(promise, i); } else { this._willSettleAt(new c(resolve => resolve(entry)), i); } } else { this._willSettleAt(resolve(entry), i); } } _eachEntry(entry, i) { if (isMaybeThenable(entry)) { this._settleMaybeThenable(entry, i); } else { this._remaining--; this._result[i] = this._makeResult(FULFILLED, i, entry); } } _settledAt(state, i, value) { let promise = this.promise; if (promise._state === PENDING) { if (this._abortOnReject && state === REJECTED) { reject(promise, value); } else { this._remaining--; this._result[i] = this._makeResult(state, i, value); if (this._remaining === 0) { fulfill(promise, this._result); } } } } _makeResult(state, i, value) { return value; } _willSettleAt(promise, i) { let enumerator = this; subscribe( promise, undefined, value => enumerator._settledAt(FULFILLED, i, value), reason => enumerator._settledAt(REJECTED, i, reason) ); } } export function makeSettledResult(state, position, value) { if (state === FULFILLED) { return { state: 'fulfilled', value: value }; } else { return { state: 'rejected', reason: value }; } }