11'use strict' ;
22
3- var asap = require ( 'asap' )
3+ var asap = require ( 'asap/raw' )
4+
5+ function noop ( ) { } ;
6+
7+ // States:
8+ //
9+ // 0 - pending
10+ // 1 - fulfilled with _value
11+ // 2 - rejected with _value
12+ // 3 - adopted the state of another promise, _value
13+ //
14+ // once the state is no longer pending (0) it is immutable
15+
16+ // All `_` prefixed properties will be reduced to `_{random number}`
17+ // at build time to obfuscate them and discourage their use.
18+ // We don't use symbols or Object.defineProperty to fully hide them
19+ // because the performance isn't good enough.
20+
21+
22+ // to avoid using try/catch inside critical functions, we
23+ // extract them to here.
24+ var LAST_ERROR = null ;
25+ var IS_ERROR = { } ;
26+ function getThen ( obj ) {
27+ try {
28+ return obj . then ;
29+ } catch ( ex ) {
30+ LAST_ERROR = ex ;
31+ return IS_ERROR ;
32+ }
33+ }
34+
35+ function tryCallOne ( fn , a ) {
36+ try {
37+ return fn ( a ) ;
38+ } catch ( ex ) {
39+ LAST_ERROR = ex ;
40+ return IS_ERROR ;
41+ }
42+ }
43+ function tryCallTwo ( fn , a , b ) {
44+ try {
45+ fn ( a , b ) ;
46+ } catch ( ex ) {
47+ LAST_ERROR = ex ;
48+ return IS_ERROR ;
49+ }
50+ }
451
552module . exports = Promise ;
653function Promise ( fn ) {
754 if ( typeof this !== 'object' ) throw new TypeError ( 'Promises must be constructed via new' )
855 if ( typeof fn !== 'function' ) throw new TypeError ( 'not a function' )
9- var state = null
10- var value = null
11- var deferreds = [ ]
12- var self = this
13-
14- this . then = function ( onFulfilled , onRejected ) {
15- return new self . constructor ( function ( resolve , reject ) {
16- handle ( new Handler ( onFulfilled , onRejected , resolve , reject ) )
17- } )
18- }
19-
20- this . state = state ;
21-
22- this . isFulfilled = function ( ) {
23- return state === true
24- }
25-
26- this . isRejected = function ( ) {
27- return state === false
56+ this . _23 = 0 ;
57+ this . _78 = null ;
58+ this . _29 = [ ] ;
59+ if ( fn === noop ) return ;
60+ doResolve ( fn , this ) ;
61+ }
62+ Promise . prototype . _7 = function ( onFulfilled , onRejected ) {
63+ var self = this ;
64+ return new this . constructor ( function ( resolve , reject ) {
65+ var res = new Promise ( noop ) ;
66+ res . then ( resolve , reject ) ;
67+ self . _3 ( new Handler ( onFulfilled , onRejected , res ) ) ;
68+ } ) ;
69+ } ;
70+ Promise . prototype . then = function ( onFulfilled , onRejected ) {
71+ if ( this . constructor !== Promise ) return this . _7 ( onFulfilled , onRejected ) ;
72+ var res = new Promise ( noop ) ;
73+ this . _3 ( new Handler ( onFulfilled , onRejected , res ) ) ;
74+ return res ;
75+ } ;
76+ Promise . prototype . _3 = function ( deferred ) {
77+ if ( this . _23 === 3 ) {
78+ this . _78 . _3 ( deferred ) ;
79+ return ;
2880 }
29-
30- this . isPending = function ( ) {
31- return state === null
81+ if ( this . _23 === 0 ) {
82+ this . _29 . push ( deferred ) ;
83+ return ;
3284 }
33-
34- this . value = function ( ) {
35- if ( ! self . isFulfilled ( ) ) {
36- throw new Error ( 'Cannot get a value of an unfulfilled promise.' )
85+ var state = this . _23 ;
86+ var value = this . _78 ;
87+ asap ( function ( ) {
88+ var cb = state === 1 ? deferred . onFulfilled : deferred . onRejected
89+ if ( cb === null ) {
90+ ( state === 1 ? deferred . promise . _67 ( value ) : deferred . promise . _30 ( value ) )
91+ return
3792 }
38-
39- return value
40- }
41-
42- this . reason = function ( ) {
43- if ( ! self . isRejected ( ) ) {
44- throw new Error ( 'Cannot get a rejection reason of a non-rejected promise.' )
93+ var ret = tryCallOne ( cb , value ) ;
94+ if ( ret === IS_ERROR ) {
95+ deferred . promise . _30 ( LAST_ERROR )
96+ } else {
97+ deferred . promise . _67 ( ret )
4598 }
46-
47- return reason
99+ } ) ;
100+ } ;
101+ Promise . prototype . _67 = function ( newValue ) {
102+ //Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
103+ if ( newValue === this ) {
104+ return this . _30 ( new TypeError ( 'A promise cannot be resolved with itself.' ) )
48105 }
49-
50- function handle ( deferred ) {
51- if ( state === null ) {
52- deferreds . push ( deferred )
53- return
106+ if ( newValue && ( typeof newValue === 'object' || typeof newValue === 'function' ) ) {
107+ var then = getThen ( newValue ) ;
108+ if ( then === IS_ERROR ) {
109+ return this . _30 ( LAST_ERROR ) ;
54110 }
55- asap ( function ( ) {
56- var cb = state ? deferred . onFulfilled : deferred . onRejected
57- if ( cb === null ) {
58- ( state ? deferred . resolve : deferred . reject ) ( value )
59- return
60- }
61- var ret
62- try {
63- ret = cb ( value )
64- }
65- catch ( e ) {
66- deferred . reject ( e )
67- return
111+ if (
112+ then === this . then &&
113+ newValue instanceof Promise &&
114+ newValue . _3 === this . _3
115+ ) {
116+ this . _23 = 3 ;
117+ this . _78 = newValue ;
118+ for ( var i = 0 ; i < this . _29 . length ; i ++ ) {
119+ newValue . _3 ( this . _29 [ i ] ) ;
68120 }
69- deferred . resolve ( ret )
70- } )
121+ return ;
122+ } else if ( typeof then === 'function' ) {
123+ doResolve ( then . bind ( newValue ) , this )
124+ return
125+ }
71126 }
127+ this . _23 = 1
128+ this . _78 = newValue
129+ this . _27 ( )
130+ }
72131
73- function resolve ( newValue ) {
74- try { //Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
75- if ( newValue === self ) throw new TypeError ( 'A promise cannot be resolved with itself.' )
76- if ( newValue && ( typeof newValue === 'object' || typeof newValue === 'function' ) ) {
77- var then = newValue . then
78- if ( typeof then === 'function' ) {
79- doResolve ( then . bind ( newValue ) , resolve , reject )
80- return
81- }
82- }
83- state = true
84- value = newValue
85- finale ( )
86- } catch ( e ) { reject ( e ) }
87- }
132+ Promise . prototype . _30 = function ( newValue ) {
133+ this . _23 = 2
134+ this . _78 = newValue
135+ this . _27 ( )
136+ }
137+ Promise . prototype . _27 = function ( ) {
138+ for ( var i = 0 ; i < this . _29 . length ; i ++ )
139+ this . _3 ( this . _29 [ i ] )
140+ this . _29 = null
141+ }
88142
89- function reject ( newValue ) {
90- state = false
91- value = newValue
92- finale ( )
143+ /**
144+ * Synchronous Inspection
145+ */
146+ Promise . prototype . isPending = function ( ) {
147+ return this . _23 === 0 ;
148+ }
149+ Promise . prototype . isFulfilled = function ( ) {
150+ return this . _23 === 1 || this . _23 === 3 ;
151+ }
152+ Promise . prototype . isRejected = function ( ) {
153+ return this . _23 === 2 ;
154+ }
155+ Promise . prototype . value = function ( ) {
156+ if ( ! this . isFulfilled ( ) ) {
157+ throw new Error ( 'Cannot get a value of an unfulfilled promise.' )
93158 }
94159
95- function finale ( ) {
96- for ( var i = 0 , len = deferreds . length ; i < len ; i ++ )
97- handle ( deferreds [ i ] )
98- deferreds = null
160+ return this . _78 ;
161+ }
162+ Promise . prototype . reason = function ( ) {
163+ if ( ! this . isRejected ( ) ) {
164+ throw new Error ( 'Cannot get a rejection reason of a non-rejected promise.' )
99165 }
100166
101- doResolve ( fn , resolve , reject )
167+ return this . _78 ;
102168}
103169
104170
105- function Handler ( onFulfilled , onRejected , resolve , reject ) {
171+ function Handler ( onFulfilled , onRejected , promise ) {
106172 this . onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null
107173 this . onRejected = typeof onRejected === 'function' ? onRejected : null
108- this . resolve = resolve
109- this . reject = reject
174+ this . promise = promise ;
110175}
111176
112177/**
@@ -115,21 +180,19 @@ function Handler(onFulfilled, onRejected, resolve, reject){
115180 *
116181 * Makes no guarantees about asynchrony.
117182 */
118- function doResolve ( fn , onFulfilled , onRejected ) {
183+ function doResolve ( fn , promise ) {
119184 var done = false ;
120- try {
121- fn ( function ( value ) {
122- if ( done ) return
123- done = true
124- onFulfilled ( value )
125- } , function ( reason ) {
126- if ( done ) return
127- done = true
128- onRejected ( reason )
129- } )
130- } catch ( ex ) {
185+ var res = tryCallTwo ( fn , function ( value ) {
131186 if ( done ) return
132187 done = true
133- onRejected ( ex )
188+ promise . _67 ( value )
189+ } , function ( reason ) {
190+ if ( done ) return
191+ done = true
192+ promise . _30 ( reason )
193+ } )
194+ if ( ! done && res === IS_ERROR ) {
195+ done = true
196+ promise . _30 ( LAST_ERROR )
134197 }
135198}
0 commit comments