스스로 하나의 Promise를 실현하다

5446 단어
var PENDING = 0,
    FULFILLED = 1,
    REJECTED = 2;
function noop() {};
Array.isArray = Array.isArray || function (a) {
    return Object.prototype.toString.call(a) === '[object Array]';
}
function needsResolver() {
  throw new TypeError('You must pass a resolver function as the first argument to the promise constructor')
}
function needsNew() {
  throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.")
}

function Promise(resolver){
    this._state = PENDING;
    this._deferredState = PENDING;
    this._result = null;
    this._deferreds = null;
    if (noop !== resolver) {
        typeof resolver !== 'function' && needsResolver();
        this instanceof Promise ? initializePromise(this, resolver) :  needsNew();
    }
}
Promise.resolve = resolve;
Promise.reject  = reject;
Promise.all  = all;
Promise.race  = race;
Promise.prototype = {
    constructor : Promise,
    then : then,
    'catch' : function _catch(onRejection) {
        return this.then(null, onRejection);
    }
}
/**
 * initializePromise   Promise    
 * @param promise Promise 
 * @param resolver   
 * @param resolvePromise  
 * @param rejectPromise  
 */
function initializePromise (promise, resolver) {
  try {
    resolver(function resolvePromise(value){
        _resolve(promise,value)
    },function rejectPromise(err){
        _reject(promise,err)
    })
  } catch (e) {

  }
}
/**
 * [_resolve resolve ]
 * @param promise [Promise ]
 * @param value   [ ]
 */
function _resolve (promise,value){
    if (promise._state !== PENDING) {
        return ;
    }
    promise._result = value;
    promise._state = FULFILLED;
    finale(promise);
}
/**
 * [_reject resolve ]
 * @param promise [Promise ]
 * @param err   [ ]
 */
function _reject (promise,err){
    if (promise._state !== PENDING) {
        return ;
    }
    promise._result = err;
    promise._state = REJECTED;
    finale(promise);
}

function finale (self) {
    if ( self._deferredState === 1 ) {
        handle(self, self._deferreds);
        self._deferreds = null;
    } 
}

function handle (self, deferred) {
    if (self._state === PENDING) {
        if (self._deferredState === 0) {
          self._deferredState = 1;
          self._deferreds = deferred;
          return;
        }
    }
    handleResolved(self, deferred)
}
function handleResolved (self, deferred) {
    var cb = self._state === FULFILLED ? deferred.onFulfilled : deferred.onRejected;
    if (cb === null) {
      if (self._state === FULFILLED) {
        _resolve(deferred.promise, self._value);
      } else {
        _reject(deferred.promise, self._value);
      }
      return;
    }
    cb(self._result);
    if ( self._state === REJECTED ) {
      _reject(deferred.promise, self._result);
    } else {
      _resolve(deferred.promise, self._result);
    }
}

function Handler(onFulfilled, onRejected, promise){
  this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
  this.onRejected = typeof onRejected === 'function' ? onRejected : null;
  this.promise = promise;
}
/**
 * [then  ]
 * @param  {[function]} resolve [resolve ]
 * @param  {[function]} reject  [reject ]
 */

function then (resolve,reject) {
    var res = new Promise(noop);
    handle(this, new Handler(resolve, reject, res));
    return res;
}

/**
 * @param  {[promise]}  object   promise 
 * @param  {[string]}   object   promise   resolve object
 */
function resolve (object) {
    var Constructor = this;
    if( object && 
        typeof object === 'object' && 
        object.constructor === Constructor
    ) {
        return object;
    }
    var promise = new Constructor(noop);
    _resolve(promise, object)
    return promise;
}

function reject (object) {
    var Constructor = this;
    var promise = new Constructor(noop);
    _reject(promise, object)
    return promise;
}

function all (arr) {
    if ( !Array.isArray(arr) ) {
        return new Error('Array Methods must be provided an Array');
    }
    var args = Array.prototype.slice.call(arr);
    return new Promise(function (resolve, reject) {
        if (args.length === 0) return resolve([]);
        var len = args.length;
        var result = [];
        function res(i,val) {
            if ( val && (typeof val === 'object' || typeof val === 'function') ) {
                if (val instanceof Promise ) {
                    if ( val._state === REJECTED ) reject(val._result);
                    if ( val._state === FULFILLED ) res(i,value);
                    if ( val._state === PENDING ) {
                        val.then(function(value) {
                            res(i,value)
                        }, function( error) {
                            reject(error)
                        })
                    } 
                    return;
                } 
            } 
            result[i] = val;
            if (--len === 0) {
              resolve(result);
            }
        }
        for (var i = 0; i < args.length; i++) {
          res(i, args[i]);
        }
    })
}
function race (arr) {
      return new Promise(function (resolve, reject) {
        arr.forEach(function(value){
          Promise.resolve(value).then(resolve, function(error){});
        });
      });
}

좋은 웹페이지 즐겨찾기