| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- import {
- objectOrFunction,
- isFunction
- } from './utils';
- import {
- asap
- } from './asap';
- import originalThen from './then';
- import originalResolve from './promise/resolve';
- export const PROMISE_ID = Math.random().toString(36).substring(2);
- function noop() {}
- const PENDING = void 0;
- const FULFILLED = 1;
- const REJECTED = 2;
- function selfFulfillment() {
- return new TypeError("You cannot resolve a promise with itself");
- }
- function cannotReturnOwn() {
- return new TypeError('A promises callback cannot return that same promise.');
- }
- function tryThen(then, value, fulfillmentHandler, rejectionHandler) {
- try {
- then.call(value, fulfillmentHandler, rejectionHandler);
- } catch(e) {
- return e;
- }
- }
- function handleForeignThenable(promise, thenable, then) {
- asap(promise => {
- let sealed = false;
- let error = tryThen(then, thenable, value => {
- if (sealed) { return; }
- sealed = true;
- if (thenable !== value) {
- resolve(promise, value);
- } else {
- fulfill(promise, value);
- }
- }, reason => {
- if (sealed) { return; }
- sealed = true;
- reject(promise, reason);
- }, 'Settle: ' + (promise._label || ' unknown promise'));
- if (!sealed && error) {
- sealed = true;
- reject(promise, error);
- }
- }, promise);
- }
- function handleOwnThenable(promise, thenable) {
- if (thenable._state === FULFILLED) {
- fulfill(promise, thenable._result);
- } else if (thenable._state === REJECTED) {
- reject(promise, thenable._result);
- } else {
- subscribe(thenable, undefined, value => resolve(promise, value),
- reason => reject(promise, reason))
- }
- }
- function handleMaybeThenable(promise, maybeThenable, then) {
- if (maybeThenable.constructor === promise.constructor &&
- then === originalThen &&
- maybeThenable.constructor.resolve === originalResolve) {
- handleOwnThenable(promise, maybeThenable);
- } else {
- if (then === undefined) {
- fulfill(promise, maybeThenable);
- } else if (isFunction(then)) {
- handleForeignThenable(promise, maybeThenable, then);
- } else {
- fulfill(promise, maybeThenable);
- }
- }
- }
- function resolve(promise, value) {
- if (promise === value) {
- reject(promise, selfFulfillment());
- } else if (objectOrFunction(value)) {
- let then;
- try {
- then = value.then;
- } catch (error) {
- reject(promise, error);
- return;
- }
- handleMaybeThenable(promise, value, then);
- } else {
- fulfill(promise, value);
- }
- }
- function publishRejection(promise) {
- if (promise._onerror) {
- promise._onerror(promise._result);
- }
- publish(promise);
- }
- function fulfill(promise, value) {
- if (promise._state !== PENDING) { return; }
- promise._result = value;
- promise._state = FULFILLED;
- if (promise._subscribers.length !== 0) {
- asap(publish, promise);
- }
- }
- function reject(promise, reason) {
- if (promise._state !== PENDING) { return; }
- promise._state = REJECTED;
- promise._result = reason;
- asap(publishRejection, promise);
- }
- function subscribe(parent, child, onFulfillment, onRejection) {
- let { _subscribers } = parent;
- let { length } = _subscribers;
- parent._onerror = null;
- _subscribers[length] = child;
- _subscribers[length + FULFILLED] = onFulfillment;
- _subscribers[length + REJECTED] = onRejection;
- if (length === 0 && parent._state) {
- asap(publish, parent);
- }
- }
- function publish(promise) {
- let subscribers = promise._subscribers;
- let settled = promise._state;
- if (subscribers.length === 0) { return; }
- let child, callback, detail = promise._result;
- for (let i = 0; i < subscribers.length; i += 3) {
- child = subscribers[i];
- callback = subscribers[i + settled];
- if (child) {
- invokeCallback(settled, child, callback, detail);
- } else {
- callback(detail);
- }
- }
- promise._subscribers.length = 0;
- }
- function invokeCallback(settled, promise, callback, detail) {
- let hasCallback = isFunction(callback),
- value, error, succeeded = true;
- if (hasCallback) {
- try {
- value = callback(detail);
- } catch (e) {
- succeeded = false;
- error = e;
- }
- if (promise === value) {
- reject(promise, cannotReturnOwn());
- return;
- }
- } else {
- value = detail;
- }
- if (promise._state !== PENDING) {
- // noop
- } else if (hasCallback && succeeded) {
- resolve(promise, value);
- } else if (succeeded === false) {
- reject(promise, error);
- } else if (settled === FULFILLED) {
- fulfill(promise, value);
- } else if (settled === REJECTED) {
- reject(promise, value);
- }
- }
- function initializePromise(promise, resolver) {
- try {
- resolver(function resolvePromise(value){
- resolve(promise, value);
- }, function rejectPromise(reason) {
- reject(promise, reason);
- });
- } catch(e) {
- reject(promise, e);
- }
- }
- let id = 0;
- function nextId() {
- return id++;
- }
- function makePromise(promise) {
- promise[PROMISE_ID] = id++;
- promise._state = undefined;
- promise._result = undefined;
- promise._subscribers = [];
- }
- export {
- nextId,
- makePromise,
- noop,
- resolve,
- reject,
- fulfill,
- subscribe,
- publish,
- publishRejection,
- initializePromise,
- invokeCallback,
- FULFILLED,
- REJECTED,
- PENDING,
- handleMaybeThenable
- };
|