split JS components
[contrib/cloudeebus.git] / src / js / cloudeebus-promise.js
1 /******************************************************************************
2  * Copyright 2012 - 2013 Intel Corporation.
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  * 
8  * http://www.apache.org/licenses/LICENSE-2.0
9  * 
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *****************************************************************************/
16
17
18
19 /*****************************************************************************/
20
21 function _processWrappers(wrappers, value) {
22         for (var i=0; i<wrappers.length; i++)
23                 wrappers[i](value);
24 }
25
26
27 function _processWrappersAsync(wrappers, value) {
28         var taskid = -1;
29         function processAsyncOnce() {
30                 _processWrappers(wrappers, value);
31                 clearInterval(taskid);
32         }
33         taskid = setInterval(processAsyncOnce, 200);
34 }
35
36
37
38 /*****************************************************************************/
39
40 cloudeebus.PromiseResolver = function(promise) {
41         this.promise = promise;
42         this.resolved = null;
43     return this;
44 };
45
46
47 cloudeebus.PromiseResolver.prototype.resolve = function(value, sync) {
48         if (this.resolved)
49                 return;
50         
51         var then = (value && value.then && value.then.apply) ? value.then : null;
52         if (then) {
53                 var self = this;                
54                 var fulfillCallback = function(arg) {
55                         self.resolve(arg, true);
56                 };      
57                 var rejectCallback = function(arg) {
58                         self.reject(arg, true);
59                 };
60                 try {
61                         then.apply(value, [fulfillCallback, rejectCallback]);
62                 }
63                 catch (e) {
64                         this.reject(cloudeebus.getError(e), true);
65                 }
66         }
67         
68         this.fulfill(value, sync);
69 };
70
71
72 cloudeebus.PromiseResolver.prototype.fulfill = function(value, sync) {
73         if (this.resolved)
74                 return;
75         
76         var promise = this.promise;
77         promise.state = "fulfilled";
78         promise.result = value;
79         
80         this.resolved = true;
81         if (sync)
82                 _processWrappers(promise._fulfillWrappers, value);
83         else
84                 _processWrappersAsync(promise._fulfillWrappers, value);
85 };
86
87
88 cloudeebus.PromiseResolver.prototype.reject = function(value, sync) {
89         if (this.resolved)
90                 return;
91         
92         var promise = this.promise;
93         promise.state = "rejected";
94         promise.result = value;
95         
96         this.resolved = true;
97         if (sync)
98                 _processWrappers(promise._rejectWrappers, value);
99         else
100                 _processWrappersAsync(promise._rejectWrappers, value);
101 };
102
103
104
105 /*****************************************************************************/
106
107 cloudeebus.Promise = function(init) {
108         this.state = "pending";
109         this.result = null;
110         this._fulfillWrappers = [];
111         this._rejectWrappers = [];
112         this.resolver = new cloudeebus.PromiseResolver(this);
113         if (init) {
114                 try {
115                         init.apply(this, [this.resolver]);
116                 }
117                 catch (e) {
118                         this.resolver.reject(cloudeebus.getError(e), true);
119                 }
120         }
121     return this;
122 };
123
124
125 cloudeebus.Promise.prototype.appendWrappers = function(fulfillWrapper, rejectWrapper) {
126         if (fulfillWrapper)
127                 this._fulfillWrappers.push(fulfillWrapper);
128         if (rejectWrapper)
129                 this._rejectWrappers.push(rejectWrapper);
130         if (this.state == "fulfilled")
131                 _processWrappersAsync(this._fulfillWrappers, this.result);
132         if (this.state == "rejected")
133                 _processWrappersAsync(this._rejectWrappers, this.result);
134 };
135
136
137 cloudeebus.Promise.prototype.then = function(fulfillCB, rejectCB) {
138         var promise = new cloudeebus.Promise();
139         var resolver = promise.resolver;
140         var fulfillWrapper, rejectWrapper;
141         
142         if (fulfillCB)
143                 fulfillWrapper = function(arg) {
144                         try {
145                                 var value = fulfillCB.apply(promise, [arg]);
146                                 resolver.resolve(value, true);
147                         }
148                         catch (e) {
149                                 resolver.reject(cloudeebus.getError(e), true);
150                         }
151                 };
152         else
153                 fulfillWrapper = function(arg) {
154                         resolver.fulfill(arg, true);
155                 };
156         
157         if (rejectCB)
158                 rejectWrapper = function(arg) {
159                         try {
160                                 var value = rejectCB.apply(promise, [arg]);
161                                 resolver.resolve(value, true);
162                         }
163                         catch (e) {
164                                 resolver.reject(cloudeebus.getError(e), true);
165                         }
166                 };
167         else
168                 rejectWrapper = function(arg) {
169                         resolver.reject(arg, true);
170                 };
171         
172         this.appendWrappers(fulfillWrapper,rejectWrapper);
173         return promise;
174 };
175
176
177 cloudeebus.Promise.prototype["catch"] = function(rejectCB) {
178         return this.then(undefined,rejectCB);
179 };
180
181
182 cloudeebus.Promise.prototype.done = function(fulfillCB, rejectCB) {
183         this.appendWrappers(fulfillCB,rejectCB);
184 };
185
186
187 cloudeebus.Promise.resolve = function(value) {
188         var promise = new cloudeebus.Promise();
189         promise.resolver.resolve(value);
190         return promise;
191 };
192
193
194 cloudeebus.Promise.fulfill = function(value) {
195         var promise = new cloudeebus.Promise();
196         promise.resolver.fulfill(value);
197         return promise;
198 };
199
200
201 cloudeebus.Promise.reject = function(value) {
202         var promise = new cloudeebus.Promise();
203         promise.resolver.reject(value);
204         return promise;
205 };
206
207
208 cloudeebus.Promise.any = function() {
209         var promise = new cloudeebus.Promise();
210         var resolver = promise.resolver;
211         var fulfillCallback = function(arg) {
212                 resolver.resolve(arg, true);
213         };
214         var rejectCallback = function(arg) {
215                 resolver.reject(arg, true);
216         };
217         if (arguments.length == 0)
218                 resolver.resolve(undefined, true);
219         else
220                 for (i in arguments) 
221                         cloudeebus.Promise.resolve(arguments[i]).appendWrappers(fulfillCallback,rejectCallback);
222         return promise;
223 };
224
225
226 cloudeebus.Promise.every = function() {
227         var promise = new cloudeebus.Promise();
228         var resolver = promise.resolver;
229         var index = 0;
230         var countdown = arguments.length;
231         var args = new Array(countdown);
232         var rejectCallback = function(arg) {
233                 resolver.reject(arg, true);
234         };
235         if (arguments.length == 0)
236                 resolver.resolve(undefined, true);
237         else
238                 for (i in arguments) {
239                         var fulfillCallback = function(arg) {
240                                 args[index] = arg;
241                                 countdown--;
242                                 if (countdown == 0)
243                                         resolver.resolve(args, true);
244                         };
245                         index++;
246                         cloudeebus.Promise.resolve(arguments[i]).appendWrappers(fulfillCallback,rejectCallback);
247                 }
248         
249         return promise;
250 };
251
252
253 cloudeebus.Promise.some = function() {
254         var promise = new cloudeebus.Promise();
255         var resolver = promise.resolver;
256         var index = 0;
257         var countdown = arguments.length;
258         var args = new Array(countdown);
259         var fulfillCallback = function(arg) {
260                 resolver.resolve(arg, true);
261         };
262         if (arguments.length == 0)
263                 resolver.resolve(undefined, true);
264         else
265                 for (i in arguments) {
266                         var rejectCallback = function(arg) {
267                                 args[index] = arg;
268                                 countdown--;
269                                 if (countdown == 0)
270                                         resolver.reject(args, true);
271                         };
272                         index++;
273                         cloudeebus.Promise.resolve(arguments[i]).appendWrappers(fulfillCallback,rejectCallback);
274                 }
275         
276         return promise;
277 };
278
279
280