1
1
'use strict' ;
2
2
3
- var asap = require ( 'asap' )
3
+ var asap = require ( 'asap/raw ' )
4
4
5
- // Use Symbol if it's available, but otherwise just
6
- // generate a random string as this is probably going
7
- // to be unique
8
- var handleSymbol = typeof Symbol === 'function' ?
9
- Symbol ( ) :
10
- (
11
- '_promise_internal_key_handle_' +
12
- Math . random ( ) . toString ( 35 ) . substr ( 2 , 10 ) + '_'
13
- )
5
+ function noop ( ) { } ;
14
6
15
7
module . exports = Promise ;
16
8
function Promise ( fn ) {
17
9
if ( typeof this !== 'object' ) throw new TypeError ( 'Promises must be constructed via new' )
18
10
if ( typeof fn !== 'function' ) throw new TypeError ( 'not a function' )
19
- var state = null
20
- var value = null
21
- var deferreds = [ ]
22
- var self = this
23
-
24
- this . then = function ( onFulfilled , onRejected ) {
25
- return new self . constructor ( function ( resolve , reject ) {
26
- handle ( new Handler ( onFulfilled , onRejected , resolve , reject ) )
27
- } )
11
+ this . _state = 0 ;
12
+ this . _value = null ;
13
+ this . _deferreds = [ ] ;
14
+ if ( fn === noop ) return ;
15
+ doResolve ( fn , this ) ;
16
+ }
17
+ Promise . prototype . _safeThen = function ( onFulfilled , onRejected ) {
18
+ var self = this ;
19
+ return new this . constructor ( function ( resolve , reject ) {
20
+ var res = new Promise ( noop ) ;
21
+ res . then ( resolve , reject ) ;
22
+ self . _handle ( new Handler ( onFulfilled , onRejected , res ) ) ;
23
+ } ) ;
24
+ } ;
25
+ Promise . prototype . then = function ( onFulfilled , onRejected ) {
26
+ if ( this . constructor !== Promise ) return this . _safeThen ( onFulfilled , onRejected ) ;
27
+ var res = new Promise ( noop ) ;
28
+ this . _handle ( new Handler ( onFulfilled , onRejected , res ) ) ;
29
+ return res ;
30
+ } ;
31
+ Promise . prototype . _handle = function ( deferred ) {
32
+ if ( this . _state === 3 ) {
33
+ this . _value . _handle ( deferred ) ;
34
+ return ;
28
35
}
29
- this . then [ handleSymbol ] = handle ;
30
- function handle ( deferred ) {
31
- return internalHandle ( deferred ) ;
36
+ if ( this . _state === 0 ) {
37
+ this . _deferreds . push ( deferred ) ;
38
+ return ;
32
39
}
33
- function internalHandle ( deferred ) {
34
- if ( state === null ) {
35
- deferreds . push ( deferred )
40
+ var state = this . _state ;
41
+ var value = this . _value ;
42
+ asap ( function ( ) {
43
+ var cb = state === 1 ? deferred . onFulfilled : deferred . onRejected
44
+ if ( cb === null ) {
45
+ ( state === 1 ? deferred . resolve ( value ) : deferred . reject ( value ) )
36
46
return
37
47
}
38
- asap ( function ( ) {
39
- var cb = state ? deferred . onFulfilled : deferred . onRejected
40
- if ( cb === null ) {
41
- ( state ? deferred . resolve : deferred . reject ) ( value )
42
- return
43
- }
44
- var ret
45
- try {
46
- ret = cb ( value )
48
+ var ret
49
+ try {
50
+ ret = cb ( value )
51
+ }
52
+ catch ( e ) {
53
+ deferred . reject ( e )
54
+ return
55
+ }
56
+ deferred . resolve ( ret )
57
+ } ) ;
58
+ } ;
59
+ Promise . prototype . _resolve = function ( newValue ) {
60
+ try { //Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
61
+ if ( newValue === this ) throw new TypeError ( 'A promise cannot be resolved with itself.' )
62
+ if ( newValue && ( typeof newValue === 'object' || typeof newValue === 'function' ) ) {
63
+ if (
64
+ newValue instanceof Promise &&
65
+ newValue . _handle === this . _handle &&
66
+ newValue . then === this . then
67
+ ) {
68
+ this . _state = 3 ;
69
+ this . _value = newValue ;
70
+ for ( var i = 0 ; i < this . _deferreds . length ; i ++ ) {
71
+ newValue . _handle ( this . _deferreds [ i ] ) ;
72
+ }
73
+ return ;
47
74
}
48
- catch ( e ) {
49
- deferred . reject ( e )
75
+ var then = newValue . then
76
+ if ( typeof then === 'function' ) {
77
+ doResolve ( then . bind ( newValue ) , this )
50
78
return
51
79
}
52
- deferred . resolve ( ret )
53
- } )
54
- }
55
-
56
- function resolve ( newValue ) {
57
- try { //Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
58
- if ( newValue === self ) throw new TypeError ( 'A promise cannot be resolved with itself.' )
59
- if ( newValue && ( typeof newValue === 'object' || typeof newValue === 'function' ) ) {
60
- var then = newValue . then
61
- if ( typeof then === 'function' ) {
62
- if ( typeof then [ handleSymbol ] === 'function' ) {
63
- // to prevent a memory leak, we adopt the value of the other promise
64
- // allowing this promise to be garbage collected as soon as nobody
65
- // has a reference to it
66
- internalHandle = then [ handleSymbol ] ;
67
- deferreds . forEach ( function ( deferred ) {
68
- internalHandle ( deferred ) ;
69
- } ) ;
70
- } else {
71
- doResolve ( then . bind ( newValue ) , resolve , reject )
72
- }
73
- return
74
- }
75
- }
76
- state = true
77
- value = newValue
78
- finale ( )
79
- } catch ( e ) { reject ( e ) }
80
- }
81
-
82
- function reject ( newValue ) {
83
- state = false
84
- value = newValue
85
- finale ( )
86
- }
87
-
88
- function finale ( ) {
89
- for ( var i = 0 , len = deferreds . length ; i < len ; i ++ )
90
- handle ( deferreds [ i ] )
91
- deferreds = null
92
- }
80
+ }
81
+ this . _state = 1
82
+ this . _value = newValue
83
+ this . _finale ( )
84
+ } catch ( e ) { this . _reject ( e ) }
85
+ }
93
86
94
- doResolve ( fn , resolve , reject )
87
+ Promise . prototype . _reject = function ( newValue ) {
88
+ this . _state = 2
89
+ this . _value = newValue
90
+ this . _finale ( )
91
+ }
92
+ Promise . prototype . _finale = function ( ) {
93
+ for ( var i = 0 ; i < this . _deferreds . length ; i ++ )
94
+ this . _handle ( this . _deferreds [ i ] )
95
+ this . _deferreds = null
95
96
}
96
97
97
98
98
- function Handler ( onFulfilled , onRejected , resolve , reject ) {
99
+ function Handler ( onFulfilled , onRejected , promise ) {
99
100
this . onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null
100
101
this . onRejected = typeof onRejected === 'function' ? onRejected : null
101
- this . resolve = resolve
102
- this . reject = reject
102
+ this . promise = promise ;
103
+ }
104
+ Handler . prototype . resolve = function ( value ) {
105
+ this . promise . _resolve ( value ) ;
106
+ } ;
107
+ Handler . prototype . reject = function ( value ) {
108
+ this . promise . _reject ( value ) ;
103
109
}
104
110
105
111
/**
@@ -108,21 +114,21 @@ function Handler(onFulfilled, onRejected, resolve, reject){
108
114
*
109
115
* Makes no guarantees about asynchrony.
110
116
*/
111
- function doResolve ( fn , onFulfilled , onRejected ) {
117
+ function doResolve ( fn , promise ) {
112
118
var done = false ;
113
119
try {
114
120
fn ( function ( value ) {
115
121
if ( done ) return
116
122
done = true
117
- onFulfilled ( value )
123
+ promise . _resolve ( value )
118
124
} , function ( reason ) {
119
125
if ( done ) return
120
126
done = true
121
- onRejected ( reason )
127
+ promise . _reject ( reason )
122
128
} )
123
129
} catch ( ex ) {
124
130
if ( done ) return
125
131
done = true
126
- onRejected ( ex )
132
+ promise . _reject ( ex )
127
133
}
128
- }
134
+ }
0 commit comments