1 var hitch = require("./base/functions").hitch, 2 define = require("./define").define, base = require("./base"); 3 4 var Promise = define(null, { 5 instance : { 6 /** @lends comb.Promise.prototype */ 7 __fired : false, 8 9 __results : null, 10 11 __error : null, 12 13 __errorCbs : null, 14 15 __cbs : null, 16 17 /** 18 * Promise object used for handling a thread 19 *@example 20 * var myFunc = function(){ 21 * var promise = new Promise(); 22 * //callback the promise after 10 Secs 23 * setTimeout(hitch(promise, "callback"), 10000); 24 * return promise; 25 * } 26 * var myFunc2 = function(){ 27 * var promises =[]; 28 * for(var i = 0; i < 10; i++){ 29 * promises.push(myFunc); 30 * } 31 * //create a new promise list with all 10 promises 32 * return new PromiseList(promises); 33 * } 34 * 35 * myFunc.then(do something...) 36 * myFunc.addCallback(do something...) 37 * myFunc.cain(myfunc).then(do something...) 38 * myFunc.cain(myfunc).addCallback(do something...) 39 * 40 * myFunc2.then(do something...) 41 * myFunc2.addCallback(do something...) 42 * myFunc2.cain(myfunc).then(do something...) 43 * myFunc2.cain(myfunc).addCallback(do something...) 44 * @memberOf comb 45 * @constructs 46 */ 47 constructor : function() { 48 this.__errorCbs = []; 49 this.__cbs = []; 50 }, 51 /** 52 * @private 53 */ 54 __resolve : function() { 55 if (!this.__fired) { 56 this.__fired = true; 57 var cbs = this.__error ? this.__errorCbs : this.__cbs, 58 len = cbs.length, i, 59 results = this.__error || this.__results; 60 for (i = 0; i < len; i++) { 61 cbs[i].apply(this, results); 62 } 63 } 64 }, 65 66 /** 67 * Add a callback to the callback chain of the promise 68 * 69 * 70 * @param {Function} cb the function to callback when the promise is resolved 71 */ 72 addCallback : function(cb) { 73 if (cb) { 74 if (this.__fired && this.__results) { 75 cb.apply(this, this.__results); 76 } else { 77 this.__cbs.push(cb); 78 } 79 } 80 return this; 81 }, 82 83 84 /** 85 * Add a callback to the errback chain of the promise 86 * 87 * @param {Function} cb the function to callback when the promise errors 88 */ 89 addErrback : function(cb) { 90 if (cb) { 91 if (this.__fired && this.__error) { 92 cb.apply(this, this.__error); 93 } else { 94 this.__errorCbs.push(cb); 95 } 96 } 97 }, 98 99 both : function(cb) { 100 this.addCallback(cb); 101 this.addErrback(cb); 102 return this; 103 }, 104 105 /** 106 * When called all functions registered as callbacks are called with the passed in results. 107 * 108 * @param anything variable number of results to pass back to listeners of the promise 109 */ 110 callback : function() { 111 if (this.__fired) { 112 throw new Error("Already fired!"); 113 } 114 this.__results = Array.prototype.slice.call(arguments); 115 this.__resolve(); 116 return this; 117 }, 118 119 /** 120 * When called all functions registered as errbacks are called with the passed in error(s) 121 * 122 * @param anything variable number of errors to pass back to listeners of the promise 123 */ 124 errback : function(i) { 125 if (this.__fired) { 126 throw new Error("Already fired!"); 127 } 128 this.__error = Array.prototype.slice.call(arguments); 129 this.__resolve(); 130 return this; 131 }, 132 133 /** 134 * Call to specify action to take after promise completes or errors 135 * 136 * @param {Function} [callback=null] function to call after the promise completes successfully 137 * @param {Function} [errback=null] function to call if the promise errors 138 */ 139 then : function(callback, errback) { 140 this.addCallback(callback); 141 this.addErrback(errback); 142 return this; 143 }, 144 145 /** 146 * Call to chaining of promises 147 * @param callback method to call that returns a promise to call after this one completes. 148 * @param errback method to call if this promise errors. 149 */ 150 chain : function(callback, errback) { 151 var promise = new Promise(); 152 this.addCallback(function(results) { 153 callback.call(this, results).then(hitch(promise, "callback"), hitch(promise, "errback")); 154 }); 155 this.addErrback(errback); 156 return promise; 157 } 158 159 } 160 }); 161 162 163 var PromiseList = define(Promise, { 164 instance : { 165 /** @lends comb.PromiseList.prototype */ 166 167 /*@private*/ 168 __results : null, 169 170 /*@private*/ 171 __errors : null, 172 173 /*@private*/ 174 __promiseLength : 0, 175 176 /*@private*/ 177 __defLength : 0, 178 179 /*@private*/ 180 __firedLength : 0, 181 182 /** 183 * 184 * PromiseList object used for handling a list of Promises 185 * @example var myFunc = function(){ 186 * var promise = new Promise(); 187 * //callback the promise after 10 Secs 188 * setTimeout(hitch(promise, "callback"), 10000); 189 * return promise; 190 * } 191 * var myFunc2 = function(){ 192 * var promises =[]; 193 * for(var i = 0; i < 10; i++){ 194 * promises.push(myFunc); 195 * } 196 * //create a new promise list with all 10 promises 197 * return new PromiseList(promises); 198 * } 199 * var pl = new comb.PomiseList([myFunc(), myFunc2()]); 200 * pl.then(do something...) 201 * pl.addCallback(do something...) 202 * pl.cain(myfunc).then(do something...) 203 * pl.cain(myfunc).addCallback(do something...) 204 * 205 * @param {comb.Promise[]} [defs=[]] the list of promises 206 * @constructs 207 * @augments comb.Promise 208 * @memberOf comb 209 * */ 210 constructor : function(defs) { 211 this.__defLength = defs.length; 212 this.__errors = []; 213 this.__results = []; 214 this.super(arguments); 215 defs.forEach(this.__addPromise, this); 216 }, 217 218 /** 219 * Add a promise to our chain 220 * @private 221 * @param promise the promise to add to our chain 222 * @param i the index of the promise in our chain 223 */ 224 __addPromise : function(promise, i) { 225 promise.addCallback(hitch(this, function() { 226 var args = Array.prototype.slice.call(arguments); 227 args.unshift(i); 228 this.callback.apply(this, args); 229 })); 230 promise.addErrback(hitch(this, function() { 231 var args = Array.prototype.slice.call(arguments); 232 args.unshift(i); 233 this.errback.apply(this, args); 234 })); 235 }, 236 237 /** 238 * Resolves the promise 239 * @private 240 */ 241 __resolve : function() { 242 if (!this.__fired) { 243 this.__fired = true; 244 var cbs = this.__errors.length ? this.__errorCbs : this.__cbs, 245 len = cbs.length, i, 246 results = this.__errors.length ? this.__errors : this.__results; 247 for (i = 0; i < len; i++) { 248 cbs[i].call(this, results); 249 } 250 } 251 }, 252 253 addCallback : function(cb) { 254 if (cb) { 255 if (this.__fired && !this.__errors.length) { 256 cb.call(this, this.__results); 257 } else { 258 this.__cbs.push(cb); 259 } 260 } 261 return this; 262 }, 263 264 addErrback : function(cb) { 265 if (cb) { 266 if (this.__fired && this.__errors.length) { 267 cb.call(this, this.__errors); 268 } else { 269 this.__errorCbs.push(cb); 270 } 271 } 272 return this; 273 }, 274 275 276 callback : function(i) { 277 if (this.__fired) { 278 throw new Error("Already fired!"); 279 } 280 this.__results[i] = (Array.prototype.slice.call(arguments)); 281 this.__firedLength++; 282 if (this.__firedLength == this.__defLength) { 283 this.__resolve(); 284 } 285 return this; 286 }, 287 288 289 errback : function(i) { 290 if (this.__fired) { 291 throw new Error("Already fired!"); 292 } 293 this.__errors[i] = Array.prototype.slice.call(arguments); 294 this.__firedLength++; 295 if (this.__firedLength == this.__defLength) { 296 this.__resolve(); 297 } 298 return this; 299 } 300 301 } 302 }); 303 exports.Promise = Promise; 304 exports.PromiseList = PromiseList;