File size: 7,591 Bytes
bc20498 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
/*!
Embeddable Minimum Strictly-Compliant Promises/A+ 1.1.1 Thenable
Copyright (c) 2013-2014 Ralf S. Engelschall (http://engelschall.com)
Licensed under The MIT License (http://opensource.org/licenses/MIT)
*/
/* promise states [Promises/A+ 2.1] */
var STATE_PENDING = 0; /* [Promises/A+ 2.1.1] */
var STATE_FULFILLED = 1; /* [Promises/A+ 2.1.2] */
var STATE_REJECTED = 2; /* [Promises/A+ 2.1.3] */
/* promise object constructor */
var api = function( executor ){
/* optionally support non-constructor/plain-function call */
if( !(this instanceof api) )
return new api( executor );
/* initialize object */
this.id = 'Thenable/1.0.7';
this.state = STATE_PENDING; /* initial state */
this.fulfillValue = undefined; /* initial value */ /* [Promises/A+ 1.3, 2.1.2.2] */
this.rejectReason = undefined; /* initial reason */ /* [Promises/A+ 1.5, 2.1.3.2] */
this.onFulfilled = []; /* initial handlers */
this.onRejected = []; /* initial handlers */
/* provide optional information-hiding proxy */
this.proxy = {
then: this.then.bind( this )
};
/* support optional executor function */
if( typeof executor === 'function' )
executor.call( this, this.fulfill.bind( this ), this.reject.bind( this ) );
};
/* promise API methods */
api.prototype = {
/* promise resolving methods */
fulfill: function( value ){ return deliver( this, STATE_FULFILLED, 'fulfillValue', value ); },
reject: function( value ){ return deliver( this, STATE_REJECTED, 'rejectReason', value ); },
/* "The then Method" [Promises/A+ 1.1, 1.2, 2.2] */
then: function( onFulfilled, onRejected ){
var curr = this;
var next = new api(); /* [Promises/A+ 2.2.7] */
curr.onFulfilled.push(
resolver( onFulfilled, next, 'fulfill' ) ); /* [Promises/A+ 2.2.2/2.2.6] */
curr.onRejected.push(
resolver( onRejected, next, 'reject' ) ); /* [Promises/A+ 2.2.3/2.2.6] */
execute( curr );
return next.proxy; /* [Promises/A+ 2.2.7, 3.3] */
}
};
/* deliver an action */
var deliver = function( curr, state, name, value ){
if( curr.state === STATE_PENDING ){
curr.state = state; /* [Promises/A+ 2.1.2.1, 2.1.3.1] */
curr[ name ] = value; /* [Promises/A+ 2.1.2.2, 2.1.3.2] */
execute( curr );
}
return curr;
};
/* execute all handlers */
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 );
};
/* execute particular set of handlers */
var execute_handlers = function( curr, name, value ){
/* global setImmediate: true */
/* global setTimeout: true */
/* short-circuit processing */
if( curr[ name ].length === 0 )
return;
/* iterate over all handlers, exactly once */
var handlers = curr[ name ];
curr[ name ] = []; /* [Promises/A+ 2.2.2.3, 2.2.3.3] */
var func = function(){
for( var i = 0; i < handlers.length; i++ )
handlers[ i ]( value ); /* [Promises/A+ 2.2.5] */
};
/* execute procedure asynchronously */ /* [Promises/A+ 2.2.4, 3.1] */
if( typeof setImmediate === 'function' )
setImmediate( func );
else
setTimeout( func, 0 );
};
/* generate a resolver function */
var resolver = function( cb, next, method ){
return function( value ){
if( typeof cb !== 'function' ) /* [Promises/A+ 2.2.1, 2.2.7.3, 2.2.7.4] */
next[ method ].call( next, value ); /* [Promises/A+ 2.2.7.3, 2.2.7.4] */
else {
var result;
try { result = cb( value ); } /* [Promises/A+ 2.2.2.1, 2.2.3.1, 2.2.5, 3.2] */
catch( e ){
next.reject( e ); /* [Promises/A+ 2.2.7.2] */
return;
}
resolve( next, result ); /* [Promises/A+ 2.2.7.1] */
}
};
};
/* "Promise Resolution Procedure" */ /* [Promises/A+ 2.3] */
var resolve = function( promise, x ){
/* sanity check arguments */ /* [Promises/A+ 2.3.1] */
if( promise === x || promise.proxy === x ){
promise.reject( new TypeError( 'cannot resolve promise with itself' ) );
return;
}
/* surgically check for a "then" method
(mainly to just call the "getter" of "then" only once) */
var then;
if( (typeof x === 'object' && x !== null) || typeof x === 'function' ){
try { then = x.then; } /* [Promises/A+ 2.3.3.1, 3.5] */
catch( e ){
promise.reject( e ); /* [Promises/A+ 2.3.3.2] */
return;
}
}
/* handle own Thenables [Promises/A+ 2.3.2]
and similar "thenables" [Promises/A+ 2.3.3] */
if( typeof then === 'function' ){
var resolved = false;
try {
/* call retrieved "then" method */ /* [Promises/A+ 2.3.3.3] */
then.call( x,
/* resolvePromise */ /* [Promises/A+ 2.3.3.3.1] */
function( y ){
if( resolved ) return; resolved = true; /* [Promises/A+ 2.3.3.3.3] */
if( y === x ) /* [Promises/A+ 3.6] */
promise.reject( new TypeError( 'circular thenable chain' ) );
else
resolve( promise, y );
},
/* rejectPromise */ /* [Promises/A+ 2.3.3.3.2] */
function( r ){
if( resolved ) return; resolved = true; /* [Promises/A+ 2.3.3.3.3] */
promise.reject( r );
}
);
}
catch( e ){
if( !resolved ) /* [Promises/A+ 2.3.3.3.3] */
promise.reject( e ); /* [Promises/A+ 2.3.3.3.4] */
}
return;
}
/* handle other values */
promise.fulfill( x ); /* [Promises/A+ 2.3.4, 2.3.3.4] */
};
// so we always have Promise.all()
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; // eslint-disable-line no-undef
|