You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							274 lines
						
					
					
						
							6.2 KiB
						
					
					
				
			
		
		
	
	
							274 lines
						
					
					
						
							6.2 KiB
						
					
					
				'use strict';
 | 
						|
var immediate = require('immediate');
 | 
						|
 | 
						|
/* istanbul ignore next */
 | 
						|
function INTERNAL() {}
 | 
						|
 | 
						|
var handlers = {};
 | 
						|
 | 
						|
var REJECTED = ['REJECTED'];
 | 
						|
var FULFILLED = ['FULFILLED'];
 | 
						|
var PENDING = ['PENDING'];
 | 
						|
 | 
						|
module.exports = Promise;
 | 
						|
 | 
						|
function Promise(resolver) {
 | 
						|
  if (typeof resolver !== 'function') {
 | 
						|
    throw new TypeError('resolver must be a function');
 | 
						|
  }
 | 
						|
  this.state = PENDING;
 | 
						|
  this.queue = [];
 | 
						|
  this.outcome = void 0;
 | 
						|
  if (resolver !== INTERNAL) {
 | 
						|
    safelyResolveThenable(this, resolver);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
Promise.prototype["finally"] = function (callback) {
 | 
						|
  if (typeof callback !== 'function') {
 | 
						|
    return this;
 | 
						|
  }
 | 
						|
  var p = this.constructor;
 | 
						|
  return this.then(resolve, reject);
 | 
						|
 | 
						|
  function resolve(value) {
 | 
						|
    function yes () {
 | 
						|
      return value;
 | 
						|
    }
 | 
						|
    return p.resolve(callback()).then(yes);
 | 
						|
  }
 | 
						|
  function reject(reason) {
 | 
						|
    function no () {
 | 
						|
      throw reason;
 | 
						|
    }
 | 
						|
    return p.resolve(callback()).then(no);
 | 
						|
  }
 | 
						|
};
 | 
						|
Promise.prototype["catch"] = function (onRejected) {
 | 
						|
  return this.then(null, onRejected);
 | 
						|
};
 | 
						|
Promise.prototype.then = function (onFulfilled, onRejected) {
 | 
						|
  if (typeof onFulfilled !== 'function' && this.state === FULFILLED ||
 | 
						|
    typeof onRejected !== 'function' && this.state === REJECTED) {
 | 
						|
    return this;
 | 
						|
  }
 | 
						|
  var promise = new this.constructor(INTERNAL);
 | 
						|
  if (this.state !== PENDING) {
 | 
						|
    var resolver = this.state === FULFILLED ? onFulfilled : onRejected;
 | 
						|
    unwrap(promise, resolver, this.outcome);
 | 
						|
  } else {
 | 
						|
    this.queue.push(new QueueItem(promise, onFulfilled, onRejected));
 | 
						|
  }
 | 
						|
 | 
						|
  return promise;
 | 
						|
};
 | 
						|
function QueueItem(promise, onFulfilled, onRejected) {
 | 
						|
  this.promise = promise;
 | 
						|
  if (typeof onFulfilled === 'function') {
 | 
						|
    this.onFulfilled = onFulfilled;
 | 
						|
    this.callFulfilled = this.otherCallFulfilled;
 | 
						|
  }
 | 
						|
  if (typeof onRejected === 'function') {
 | 
						|
    this.onRejected = onRejected;
 | 
						|
    this.callRejected = this.otherCallRejected;
 | 
						|
  }
 | 
						|
}
 | 
						|
QueueItem.prototype.callFulfilled = function (value) {
 | 
						|
  handlers.resolve(this.promise, value);
 | 
						|
};
 | 
						|
QueueItem.prototype.otherCallFulfilled = function (value) {
 | 
						|
  unwrap(this.promise, this.onFulfilled, value);
 | 
						|
};
 | 
						|
QueueItem.prototype.callRejected = function (value) {
 | 
						|
  handlers.reject(this.promise, value);
 | 
						|
};
 | 
						|
QueueItem.prototype.otherCallRejected = function (value) {
 | 
						|
  unwrap(this.promise, this.onRejected, value);
 | 
						|
};
 | 
						|
 | 
						|
function unwrap(promise, func, value) {
 | 
						|
  immediate(function () {
 | 
						|
    var returnValue;
 | 
						|
    try {
 | 
						|
      returnValue = func(value);
 | 
						|
    } catch (e) {
 | 
						|
      return handlers.reject(promise, e);
 | 
						|
    }
 | 
						|
    if (returnValue === promise) {
 | 
						|
      handlers.reject(promise, new TypeError('Cannot resolve promise with itself'));
 | 
						|
    } else {
 | 
						|
      handlers.resolve(promise, returnValue);
 | 
						|
    }
 | 
						|
  });
 | 
						|
}
 | 
						|
 | 
						|
handlers.resolve = function (self, value) {
 | 
						|
  var result = tryCatch(getThen, value);
 | 
						|
  if (result.status === 'error') {
 | 
						|
    return handlers.reject(self, result.value);
 | 
						|
  }
 | 
						|
  var thenable = result.value;
 | 
						|
 | 
						|
  if (thenable) {
 | 
						|
    safelyResolveThenable(self, thenable);
 | 
						|
  } else {
 | 
						|
    self.state = FULFILLED;
 | 
						|
    self.outcome = value;
 | 
						|
    var i = -1;
 | 
						|
    var len = self.queue.length;
 | 
						|
    while (++i < len) {
 | 
						|
      self.queue[i].callFulfilled(value);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return self;
 | 
						|
};
 | 
						|
handlers.reject = function (self, error) {
 | 
						|
  self.state = REJECTED;
 | 
						|
  self.outcome = error;
 | 
						|
  var i = -1;
 | 
						|
  var len = self.queue.length;
 | 
						|
  while (++i < len) {
 | 
						|
    self.queue[i].callRejected(error);
 | 
						|
  }
 | 
						|
  return self;
 | 
						|
};
 | 
						|
 | 
						|
function getThen(obj) {
 | 
						|
  // Make sure we only access the accessor once as required by the spec
 | 
						|
  var then = obj && obj.then;
 | 
						|
  if (obj && (typeof obj === 'object' || typeof obj === 'function') && typeof then === 'function') {
 | 
						|
    return function appyThen() {
 | 
						|
      then.apply(obj, arguments);
 | 
						|
    };
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
function safelyResolveThenable(self, thenable) {
 | 
						|
  // Either fulfill, reject or reject with error
 | 
						|
  var called = false;
 | 
						|
  function onError(value) {
 | 
						|
    if (called) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    called = true;
 | 
						|
    handlers.reject(self, value);
 | 
						|
  }
 | 
						|
 | 
						|
  function onSuccess(value) {
 | 
						|
    if (called) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    called = true;
 | 
						|
    handlers.resolve(self, value);
 | 
						|
  }
 | 
						|
 | 
						|
  function tryToUnwrap() {
 | 
						|
    thenable(onSuccess, onError);
 | 
						|
  }
 | 
						|
 | 
						|
  var result = tryCatch(tryToUnwrap);
 | 
						|
  if (result.status === 'error') {
 | 
						|
    onError(result.value);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
function tryCatch(func, value) {
 | 
						|
  var out = {};
 | 
						|
  try {
 | 
						|
    out.value = func(value);
 | 
						|
    out.status = 'success';
 | 
						|
  } catch (e) {
 | 
						|
    out.status = 'error';
 | 
						|
    out.value = e;
 | 
						|
  }
 | 
						|
  return out;
 | 
						|
}
 | 
						|
 | 
						|
Promise.resolve = resolve;
 | 
						|
function resolve(value) {
 | 
						|
  if (value instanceof this) {
 | 
						|
    return value;
 | 
						|
  }
 | 
						|
  return handlers.resolve(new this(INTERNAL), value);
 | 
						|
}
 | 
						|
 | 
						|
Promise.reject = reject;
 | 
						|
function reject(reason) {
 | 
						|
  var promise = new this(INTERNAL);
 | 
						|
  return handlers.reject(promise, reason);
 | 
						|
}
 | 
						|
 | 
						|
Promise.all = all;
 | 
						|
function all(iterable) {
 | 
						|
  var self = this;
 | 
						|
  if (Object.prototype.toString.call(iterable) !== '[object Array]') {
 | 
						|
    return this.reject(new TypeError('must be an array'));
 | 
						|
  }
 | 
						|
 | 
						|
  var len = iterable.length;
 | 
						|
  var called = false;
 | 
						|
  if (!len) {
 | 
						|
    return this.resolve([]);
 | 
						|
  }
 | 
						|
 | 
						|
  var values = new Array(len);
 | 
						|
  var resolved = 0;
 | 
						|
  var i = -1;
 | 
						|
  var promise = new this(INTERNAL);
 | 
						|
 | 
						|
  while (++i < len) {
 | 
						|
    allResolver(iterable[i], i);
 | 
						|
  }
 | 
						|
  return promise;
 | 
						|
  function allResolver(value, i) {
 | 
						|
    self.resolve(value).then(resolveFromAll, function (error) {
 | 
						|
      if (!called) {
 | 
						|
        called = true;
 | 
						|
        handlers.reject(promise, error);
 | 
						|
      }
 | 
						|
    });
 | 
						|
    function resolveFromAll(outValue) {
 | 
						|
      values[i] = outValue;
 | 
						|
      if (++resolved === len && !called) {
 | 
						|
        called = true;
 | 
						|
        handlers.resolve(promise, values);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
Promise.race = race;
 | 
						|
function race(iterable) {
 | 
						|
  var self = this;
 | 
						|
  if (Object.prototype.toString.call(iterable) !== '[object Array]') {
 | 
						|
    return this.reject(new TypeError('must be an array'));
 | 
						|
  }
 | 
						|
 | 
						|
  var len = iterable.length;
 | 
						|
  var called = false;
 | 
						|
  if (!len) {
 | 
						|
    return this.resolve([]);
 | 
						|
  }
 | 
						|
 | 
						|
  var i = -1;
 | 
						|
  var promise = new this(INTERNAL);
 | 
						|
 | 
						|
  while (++i < len) {
 | 
						|
    resolver(iterable[i]);
 | 
						|
  }
 | 
						|
  return promise;
 | 
						|
  function resolver(value) {
 | 
						|
    self.resolve(value).then(function (response) {
 | 
						|
      if (!called) {
 | 
						|
        called = true;
 | 
						|
        handlers.resolve(promise, response);
 | 
						|
      }
 | 
						|
    }, function (error) {
 | 
						|
      if (!called) {
 | 
						|
        called = true;
 | 
						|
        handlers.reject(promise, error);
 | 
						|
      }
 | 
						|
    });
 | 
						|
  }
 | 
						|
}
 |