1
+ var EventEmitter = require ( 'events' ) . EventEmitter ;
2
+
1
3
/**
2
4
* Promises states according to the A+ Specification
5
+ *
3
6
* @readOnly
4
- * @enum {number }
7
+ * @enum {Number }
5
8
*/
6
9
var State = {
7
10
PENDING : 0 ,
8
11
FULFILLED : 1 ,
9
12
REJECTED : 2
10
13
} ;
11
14
12
- var Promise = module . exports = function ( ) { } ;
15
+ /**
16
+ * Executes a function asynchronously. Prefers setImmediate but will fallback to
17
+ * process.nextTick for older versions of node.
18
+ *
19
+ * @type {Function }
20
+ */
21
+ var next = typeof setImmediate === 'function' ? setImmediate : procees . nextTick ;
22
+
23
+ /**
24
+ * Tests if a variable is a function
25
+ *
26
+ * @param {Object } arg The argument to test
27
+ * @return {Boolean } Whether or not the argument is a function
28
+ */
29
+ var isFunction = function ( arg ) {
30
+ return typeof arg === 'function' ;
31
+ } ;
32
+
33
+ /**
34
+ * Triggers the promise events
35
+ *
36
+ * @param {Promise } promise The promise to trigger
37
+ */
38
+ var trigger = function ( promise ) {
39
+ if ( promise . state === State . FULFILLED ) {
40
+ next ( function ( ) {
41
+ promise . events . emit ( 'fulfilled' , promise . value )
42
+ } ) ;
43
+ }
44
+
45
+ if ( promise . state === State . REJECTED ) {
46
+ next ( function ( ) {
47
+ promise . events . emit ( 'rejected' , promise . value ) ;
48
+ } ) ;
49
+ }
50
+ } ;
51
+
52
+ /**
53
+ * Resolves a promise and triggers the promises
54
+ *
55
+ * @param {Promise } promise The promise to resolve
56
+ * @param {State } state The new state of the promise
57
+ * @param {Object } value The new value of the promise
58
+ * @return {State } The current state of the promise
59
+ */
60
+ var resolve = function ( promise , state , value ) {
61
+ // Cannot transition from FULFILLED or REJECTED
62
+ if ( promise . state === State . FULFILLED || promise . state === State . REJECTED ) {
63
+ return promise . state ;
64
+ }
65
+
66
+ // Must have a value for value
67
+ if ( state === State . FULFILLED && arguments . length < 3 ) {
68
+ return promise . state ;
69
+ }
70
+
71
+ // Must have a reason for rejected
72
+ if ( state === State . REJECTED && ! value ) {
73
+ return promise . state ;
74
+ }
75
+
76
+ promise . state = state ;
77
+ promise . value = value ;
78
+
79
+ trigger ( promise ) ;
80
+
81
+ return promise . state ;
82
+ } ;
83
+
84
+ /**
85
+ * Promise
86
+ * @class Promise implementing the Promises/A+ Specification
87
+ */
88
+ var Promise = module . exports = function ( ) {
89
+ this . state = State . PENDING ;
90
+ this . events = new EventEmitter ( ) ;
91
+ } ;
92
+
93
+ /**
94
+ * A+ Then specification
95
+ *
96
+ * @param {Function } onFulfilled Called when the promise succeeds
97
+ * @param {Function } onRejected Called when the promise fails
98
+ * @return {Promise } The new promise
99
+ */
100
+ Promise . prototype . then = function ( onFulfilled , onRejected ) {
101
+ var promise = new Promise ( ) ;
102
+
103
+ if ( isFunction ( onFulfilled ) ) {
104
+ this . events . once ( 'fulfilled' , function ( value ) {
105
+ promise . fulfill ( onFulfilled ( value ) ) ;
106
+ } ) ;
107
+ }
108
+
109
+ if ( isFunction ( onRejected ) ) {
110
+ this . events . once ( 'rejected' , function ( reason ) {
111
+ promise . reject ( onRejected ( reason ) ) ;
112
+ } ) ;
113
+ }
114
+
115
+ trigger ( this ) ;
116
+
117
+ return promise ;
118
+ } ;
119
+
120
+ /**
121
+ * Fulfills the promise with a value
122
+ *
123
+ * @param {Object } value
124
+ * @return {State } The state of the promise
125
+ */
126
+ Promise . prototype . fulfill = function ( value ) {
127
+ return resolve ( this , State . FULFILLED , value ) ;
128
+ } ;
129
+
130
+ /**
131
+ * Rejects the promise with a reason
132
+ *
133
+ * @param {Error } reason The reason the promise failed
134
+ * @return {State } The state of the promise
135
+ */
136
+ Promise . prototype . reject = function ( reason ) {
137
+ resolve ( this , State . REJECTED , reason ) ;
138
+ } ;
0 commit comments