|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var STATE_PENDING = 0; |
|
var STATE_FULFILLED = 1; |
|
var STATE_REJECTED = 2; |
|
|
|
|
|
var api = function( executor ){ |
|
|
|
if( !(this instanceof api) ) |
|
return new api( executor ); |
|
|
|
|
|
this.id = 'Thenable/1.0.7'; |
|
this.state = STATE_PENDING; |
|
this.fulfillValue = undefined; |
|
this.rejectReason = undefined; |
|
this.onFulfilled = []; |
|
this.onRejected = []; |
|
|
|
|
|
this.proxy = { |
|
then: this.then.bind( this ) |
|
}; |
|
|
|
|
|
if( typeof executor === 'function' ) |
|
executor.call( this, this.fulfill.bind( this ), this.reject.bind( this ) ); |
|
}; |
|
|
|
|
|
api.prototype = { |
|
|
|
fulfill: function( value ){ return deliver( this, STATE_FULFILLED, 'fulfillValue', value ); }, |
|
reject: function( value ){ return deliver( this, STATE_REJECTED, 'rejectReason', value ); }, |
|
|
|
|
|
then: function( onFulfilled, onRejected ){ |
|
var curr = this; |
|
var next = new api(); |
|
curr.onFulfilled.push( |
|
resolver( onFulfilled, next, 'fulfill' ) ); |
|
curr.onRejected.push( |
|
resolver( onRejected, next, 'reject' ) ); |
|
execute( curr ); |
|
return next.proxy; |
|
} |
|
}; |
|
|
|
|
|
var deliver = function( curr, state, name, value ){ |
|
if( curr.state === STATE_PENDING ){ |
|
curr.state = state; |
|
curr[ name ] = value; |
|
execute( curr ); |
|
} |
|
return curr; |
|
}; |
|
|
|
|
|
var execute = function( curr ){ |
|
if( curr.state === STATE_FULFILLED ) |
|
execute_handlers( curr, 'onFulfilled', curr.fulfillValue ); |
|
else if( curr.state === STATE_REJECTED ) |
|
execute_handlers( curr, 'onRejected', curr.rejectReason ); |
|
}; |
|
|
|
|
|
var execute_handlers = function( curr, name, value ){ |
|
|
|
|
|
|
|
|
|
if( curr[ name ].length === 0 ) |
|
return; |
|
|
|
|
|
var handlers = curr[ name ]; |
|
curr[ name ] = []; |
|
var func = function(){ |
|
for( var i = 0; i < handlers.length; i++ ) |
|
handlers[ i ]( value ); |
|
}; |
|
|
|
|
|
if( typeof setImmediate === 'function' ) |
|
setImmediate( func ); |
|
else |
|
setTimeout( func, 0 ); |
|
}; |
|
|
|
|
|
var resolver = function( cb, next, method ){ |
|
return function( value ){ |
|
if( typeof cb !== 'function' ) |
|
next[ method ].call( next, value ); |
|
else { |
|
var result; |
|
try { result = cb( value ); } |
|
catch( e ){ |
|
next.reject( e ); |
|
return; |
|
} |
|
resolve( next, result ); |
|
} |
|
}; |
|
}; |
|
|
|
|
|
var resolve = function( promise, x ){ |
|
|
|
if( promise === x || promise.proxy === x ){ |
|
promise.reject( new TypeError( 'cannot resolve promise with itself' ) ); |
|
return; |
|
} |
|
|
|
|
|
|
|
var then; |
|
if( (typeof x === 'object' && x !== null) || typeof x === 'function' ){ |
|
try { then = x.then; } |
|
catch( e ){ |
|
promise.reject( e ); |
|
return; |
|
} |
|
} |
|
|
|
|
|
|
|
if( typeof then === 'function' ){ |
|
var resolved = false; |
|
try { |
|
|
|
then.call( x, |
|
|
|
function( y ){ |
|
if( resolved ) return; resolved = true; |
|
if( y === x ) |
|
promise.reject( new TypeError( 'circular thenable chain' ) ); |
|
else |
|
resolve( promise, y ); |
|
}, |
|
|
|
|
|
function( r ){ |
|
if( resolved ) return; resolved = true; |
|
promise.reject( r ); |
|
} |
|
); |
|
} |
|
catch( e ){ |
|
if( !resolved ) |
|
promise.reject( e ); |
|
} |
|
return; |
|
} |
|
|
|
|
|
promise.fulfill( x ); |
|
}; |
|
|
|
|
|
api.all = function( ps ){ |
|
return new api(function( resolveAll, rejectAll ){ |
|
var vals = new Array( ps.length ); |
|
var doneCount = 0; |
|
|
|
var fulfill = function( i, val ){ |
|
vals[ i ] = val; |
|
doneCount++; |
|
|
|
if( doneCount === ps.length ){ |
|
resolveAll( vals ); |
|
} |
|
}; |
|
|
|
for( var i = 0; i < ps.length; i++ ){ |
|
(function( i ){ |
|
var p = ps[i]; |
|
var isPromise = p != null && p.then != null; |
|
|
|
if( isPromise ){ |
|
p.then( function( val ){ |
|
fulfill( i, val ); |
|
}, function( err ){ |
|
rejectAll( err ); |
|
} ); |
|
} else { |
|
var val = p; |
|
fulfill( i, val ); |
|
} |
|
})( i ); |
|
} |
|
|
|
} ); |
|
}; |
|
|
|
api.resolve = function( val ){ |
|
return new api(function( resolve, reject ){ resolve( val ); }); |
|
}; |
|
|
|
api.reject = function( val ){ |
|
return new api(function( resolve, reject ){ reject( val ); }); |
|
}; |
|
|
|
export default typeof Promise !== 'undefined' ? Promise : api; |
|
|