1
1
'use strict' ;
2
2
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
+ }
4
51
5
52
module . exports = Promise ;
6
53
function Promise ( fn ) {
7
54
if ( typeof this !== 'object' ) throw new TypeError ( 'Promises must be constructed via new' )
8
55
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 ;
28
80
}
29
-
30
- this . isPending = function ( ) {
31
- return state === null
81
+ if ( this . _23 === 0 ) {
82
+ this . _29 . push ( deferred ) ;
83
+ return ;
32
84
}
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
37
92
}
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 )
45
98
}
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.' ) )
48
105
}
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 ) ;
54
110
}
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 ] ) ;
68
120
}
69
- deferred . resolve ( ret )
70
- } )
121
+ return ;
122
+ } else if ( typeof then === 'function' ) {
123
+ doResolve ( then . bind ( newValue ) , this )
124
+ return
125
+ }
71
126
}
127
+ this . _23 = 1
128
+ this . _78 = newValue
129
+ this . _27 ( )
130
+ }
72
131
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
+ }
88
142
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.' )
93
158
}
94
159
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.' )
99
165
}
100
166
101
- doResolve ( fn , resolve , reject )
167
+ return this . _78 ;
102
168
}
103
169
104
170
105
- function Handler ( onFulfilled , onRejected , resolve , reject ) {
171
+ function Handler ( onFulfilled , onRejected , promise ) {
106
172
this . onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null
107
173
this . onRejected = typeof onRejected === 'function' ? onRejected : null
108
- this . resolve = resolve
109
- this . reject = reject
174
+ this . promise = promise ;
110
175
}
111
176
112
177
/**
@@ -115,21 +180,19 @@ function Handler(onFulfilled, onRejected, resolve, reject){
115
180
*
116
181
* Makes no guarantees about asynchrony.
117
182
*/
118
- function doResolve ( fn , onFulfilled , onRejected ) {
183
+ function doResolve ( fn , promise ) {
119
184
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 ) {
131
186
if ( done ) return
132
187
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 )
134
197
}
135
198
}
0 commit comments