async.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojox.lang.async"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.lang.async"] = true;
  8. dojo.provide("dojox.lang.async");
  9. (function(){
  10. var d = dojo, Deferred = d.Deferred, each = d.forEach, some = d.some,
  11. async = dojox.lang.async, aps = Array.prototype.slice,
  12. opts = Object.prototype.toString;
  13. async.seq = function(x){
  14. // summary:
  15. // Executes functions sequentially. Waits if any of them returns Deferred.
  16. var fs = opts.call(x) == "[object Array]" ? x : arguments;
  17. return function(init){
  18. var x = new Deferred();
  19. each(fs, function(f){ x.addCallback(f); });
  20. x.callback(init);
  21. return x;
  22. };
  23. };
  24. async.par = function(x){
  25. // summary:
  26. // Executes functions in parallel. Waits for all of them to finish.
  27. var fs = opts.call(x) == "[object Array]" ? x : arguments;
  28. return function(init){
  29. var results = new Array(fs.length),
  30. cancel = function(){
  31. each(results, function(v){
  32. if(v instanceof Deferred && v.fired < 0){
  33. v.cancel();
  34. }
  35. });
  36. },
  37. x = new Deferred(cancel),
  38. ready = fs.length;
  39. each(fs, function(f, i){
  40. var x;
  41. try {
  42. x = f(init);
  43. }catch(e){
  44. x = e;
  45. }
  46. results[i] = x;
  47. });
  48. var failed = some(results, function(v){
  49. if(v instanceof Error){
  50. cancel();
  51. x.errback(v);
  52. return true;
  53. }
  54. return false;
  55. });
  56. if(!failed){
  57. each(results, function(v, i){
  58. if(v instanceof Deferred){
  59. v.addCallbacks(
  60. function(v){
  61. results[i] = v;
  62. if(!--ready){
  63. x.callback(results);
  64. }
  65. },
  66. function(v){
  67. cancel();
  68. x.errback(v);
  69. }
  70. );
  71. }else{
  72. --ready;
  73. }
  74. });
  75. }
  76. if(!ready){
  77. x.callback(results);
  78. }
  79. return x;
  80. };
  81. };
  82. async.any = function(x){
  83. // summary:
  84. // Executes functions in parallel. As soon as one of them finishes
  85. // cancels the rest.
  86. var fs = opts.call(x) == "[object Array]" ? x : arguments;
  87. return function(init){
  88. var results = new Array(fs.length), noResult = true;
  89. cancel = function(index){
  90. each(results, function(v, i){
  91. if(i != index && v instanceof Deferred && v.fired < 0){
  92. v.cancel();
  93. }
  94. });
  95. },
  96. x = new Deferred(cancel);
  97. each(fs, function(f, i){
  98. var x;
  99. try {
  100. x = f(init);
  101. }catch(e){
  102. x = e;
  103. }
  104. results[i] = x;
  105. });
  106. var done = some(results, function(v, i){
  107. if(!(v instanceof Deferred)){
  108. cancel(i);
  109. x.callback(v);
  110. return true;
  111. }
  112. return false;
  113. });
  114. if(!done){
  115. each(results, function(v, i){
  116. v.addBoth(
  117. function(v){
  118. if(noResult){
  119. noResult = false;
  120. cancel(i);
  121. x.callback(v);
  122. }
  123. }
  124. );
  125. });
  126. }
  127. return x;
  128. };
  129. };
  130. async.select = function(cond, x){
  131. // summary:
  132. // Executes a condition, waits for it if necessary, and executes
  133. // Nth function from list.
  134. var fs = opts.call(x) == "[object Array]" ? x : aps.call(arguments, 1);
  135. return function(init){
  136. return new Deferred().addCallback(cond).addCallback(function(v){
  137. if(typeof v == "number" && v >= 0 && v < fs.length){
  138. return fs[v](init);
  139. }else{
  140. return new Error("async.select: out of range");
  141. }
  142. }).callback(init);
  143. };
  144. };
  145. async.ifThen = function(cond, ifTrue, ifFalse){
  146. // summary:
  147. // Executes a condition, waits for it if necessary, and executes
  148. // one of two functions.
  149. return function(init){
  150. return new Deferred().addCallback(cond).addCallback(function(v){
  151. return (v ? ifTrue : ifFalse)(init);
  152. }).callback(init);
  153. };
  154. };
  155. async.loop = function(cond, body){
  156. // summary:
  157. // Executes a condition, waits for it if necessary, and executes
  158. // the body, if truthy value was returned.
  159. // Then it repeats the cycle until the condition function returns
  160. // a falsy value.
  161. return function(init){
  162. var x, y = new Deferred(function(){ x.cancel(); });
  163. function ifErr(v){ y.errback(v); }
  164. function loop(v){
  165. if(v){
  166. x.addCallback(body).addCallback(setUp);
  167. }else{
  168. y.callback(v);
  169. }
  170. return v;
  171. }
  172. function setUp(init){
  173. x = new Deferred().
  174. addCallback(cond).
  175. addCallback(loop).
  176. addErrback(ifErr);
  177. x.callback(init);
  178. }
  179. setUp(init);
  180. return y;
  181. };
  182. };
  183. })();
  184. /*
  185. Design decisions:
  186. seq() - behaves like the normal Deferred callback chain.
  187. par() - if error, all pending Deferreds are cancelled and the error is signaled,
  188. otherwise return an array of all results.
  189. any() - just like par() but only one result is returned.
  190. select() - any error is returned, otherwise the selected result is returned.
  191. loop() - any error is returned, otherwise the last result is returned.
  192. */
  193. }