@@ -4,13 +4,47 @@ var asap = require('asap/raw')
4
4
5
5
function noop ( ) { } ;
6
6
7
- var thenError = null ;
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 ;
8
25
var IS_ERROR = { } ;
9
26
function getThen ( obj ) {
10
27
try {
11
28
return obj . then ;
12
29
} catch ( ex ) {
13
- thenError = 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 ;
14
48
return IS_ERROR ;
15
49
}
16
50
}
@@ -53,18 +87,15 @@ Promise.prototype._handle = function(deferred) {
53
87
asap ( function ( ) {
54
88
var cb = state === 1 ? deferred . onFulfilled : deferred . onRejected
55
89
if ( cb === null ) {
56
- ( state === 1 ? deferred . resolve ( value ) : deferred . reject ( value ) )
90
+ ( state === 1 ? deferred . promise . _resolve ( value ) : deferred . promise . _reject ( value ) )
57
91
return
58
92
}
59
- var ret
60
- try {
61
- ret = cb ( value )
62
- }
63
- catch ( e ) {
64
- deferred . reject ( e )
65
- return
93
+ var ret = tryCallOne ( cb , value ) ;
94
+ if ( ret === IS_ERROR ) {
95
+ deferred . promise . _reject ( LAST_ERROR )
96
+ } else {
97
+ deferred . promise . _resolve ( ret )
66
98
}
67
- deferred . resolve ( ret )
68
99
} ) ;
69
100
} ;
70
101
Promise . prototype . _resolve = function ( newValue ) {
@@ -75,7 +106,7 @@ Promise.prototype._resolve = function(newValue) {
75
106
if ( newValue && ( typeof newValue === 'object' || typeof newValue === 'function' ) ) {
76
107
var then = getThen ( newValue ) ;
77
108
if ( then === IS_ERROR ) {
78
- return this . _reject ( thenError ) ;
109
+ return this . _reject ( LAST_ERROR ) ;
79
110
}
80
111
if (
81
112
then === this . then &&
@@ -115,12 +146,6 @@ function Handler(onFulfilled, onRejected, promise){
115
146
this . onRejected = typeof onRejected === 'function' ? onRejected : null
116
147
this . promise = promise ;
117
148
}
118
- Handler . prototype . resolve = function ( value ) {
119
- this . promise . _resolve ( value ) ;
120
- } ;
121
- Handler . prototype . reject = function ( value ) {
122
- this . promise . _reject ( value ) ;
123
- }
124
149
125
150
/**
126
151
* Take a potentially misbehaving resolver function and make sure
@@ -130,19 +155,17 @@ Handler.prototype.reject = function (value) {
130
155
*/
131
156
function doResolve ( fn , promise ) {
132
157
var done = false ;
133
- try {
134
- fn ( function ( value ) {
135
- if ( done ) return
136
- done = true
137
- promise . _resolve ( value )
138
- } , function ( reason ) {
139
- if ( done ) return
140
- done = true
141
- promise . _reject ( reason )
142
- } )
143
- } catch ( ex ) {
158
+ var res = tryCallTwo ( fn , function ( value ) {
144
159
if ( done ) return
145
160
done = true
146
- promise . _reject ( ex )
161
+ promise . _resolve ( value )
162
+ } , function ( reason ) {
163
+ if ( done ) return
164
+ done = true
165
+ promise . _reject ( reason )
166
+ } )
167
+ if ( ! done && res === IS_ERROR ) {
168
+ done = true
169
+ promise . _reject ( LAST_ERROR )
147
170
}
148
171
}
0 commit comments