1 | dojo.provide("dojox.lang.async"); |
---|
2 | |
---|
3 | (function(){ |
---|
4 | var d = dojo, Deferred = d.Deferred, each = d.forEach, some = d.some, |
---|
5 | async = dojox.lang.async, aps = Array.prototype.slice, |
---|
6 | opts = Object.prototype.toString; |
---|
7 | |
---|
8 | async.seq = function(x){ |
---|
9 | // summary: |
---|
10 | // Executes functions sequentially. Waits if any of them returns Deferred. |
---|
11 | var fs = opts.call(x) == "[object Array]" ? x : arguments; |
---|
12 | return function(init){ |
---|
13 | var x = new Deferred(); |
---|
14 | each(fs, function(f){ x.addCallback(f); }); |
---|
15 | x.callback(init); |
---|
16 | return x; |
---|
17 | }; |
---|
18 | }; |
---|
19 | |
---|
20 | async.par = function(x){ |
---|
21 | // summary: |
---|
22 | // Executes functions in parallel. Waits for all of them to finish. |
---|
23 | var fs = opts.call(x) == "[object Array]" ? x : arguments; |
---|
24 | return function(init){ |
---|
25 | var results = new Array(fs.length), |
---|
26 | cancel = function(){ |
---|
27 | each(results, function(v){ |
---|
28 | if(v instanceof Deferred && v.fired < 0){ |
---|
29 | v.cancel(); |
---|
30 | } |
---|
31 | }); |
---|
32 | }, |
---|
33 | x = new Deferred(cancel), |
---|
34 | ready = fs.length; |
---|
35 | each(fs, function(f, i){ |
---|
36 | var x; |
---|
37 | try { |
---|
38 | x = f(init); |
---|
39 | }catch(e){ |
---|
40 | x = e; |
---|
41 | } |
---|
42 | results[i] = x; |
---|
43 | }); |
---|
44 | var failed = some(results, function(v){ |
---|
45 | if(v instanceof Error){ |
---|
46 | cancel(); |
---|
47 | x.errback(v); |
---|
48 | return true; |
---|
49 | } |
---|
50 | return false; |
---|
51 | }); |
---|
52 | if(!failed){ |
---|
53 | each(results, function(v, i){ |
---|
54 | if(v instanceof Deferred){ |
---|
55 | v.addCallbacks( |
---|
56 | function(v){ |
---|
57 | results[i] = v; |
---|
58 | if(!--ready){ |
---|
59 | x.callback(results); |
---|
60 | } |
---|
61 | }, |
---|
62 | function(v){ |
---|
63 | cancel(); |
---|
64 | x.errback(v); |
---|
65 | } |
---|
66 | ); |
---|
67 | }else{ |
---|
68 | --ready; |
---|
69 | } |
---|
70 | }); |
---|
71 | } |
---|
72 | if(!ready){ |
---|
73 | x.callback(results); |
---|
74 | } |
---|
75 | return x; |
---|
76 | }; |
---|
77 | }; |
---|
78 | |
---|
79 | async.any = function(x){ |
---|
80 | // summary: |
---|
81 | // Executes functions in parallel. As soon as one of them finishes |
---|
82 | // cancels the rest. |
---|
83 | var fs = opts.call(x) == "[object Array]" ? x : arguments; |
---|
84 | return function(init){ |
---|
85 | var results = new Array(fs.length), noResult = true; |
---|
86 | cancel = function(index){ |
---|
87 | each(results, function(v, i){ |
---|
88 | if(i != index && v instanceof Deferred && v.fired < 0){ |
---|
89 | v.cancel(); |
---|
90 | } |
---|
91 | }); |
---|
92 | }, |
---|
93 | x = new Deferred(cancel); |
---|
94 | each(fs, function(f, i){ |
---|
95 | var x; |
---|
96 | try { |
---|
97 | x = f(init); |
---|
98 | }catch(e){ |
---|
99 | x = e; |
---|
100 | } |
---|
101 | results[i] = x; |
---|
102 | }); |
---|
103 | var done = some(results, function(v, i){ |
---|
104 | if(!(v instanceof Deferred)){ |
---|
105 | cancel(i); |
---|
106 | x.callback(v); |
---|
107 | return true; |
---|
108 | } |
---|
109 | return false; |
---|
110 | }); |
---|
111 | if(!done){ |
---|
112 | each(results, function(v, i){ |
---|
113 | v.addBoth( |
---|
114 | function(v){ |
---|
115 | if(noResult){ |
---|
116 | noResult = false; |
---|
117 | cancel(i); |
---|
118 | x.callback(v); |
---|
119 | } |
---|
120 | } |
---|
121 | ); |
---|
122 | }); |
---|
123 | } |
---|
124 | return x; |
---|
125 | }; |
---|
126 | }; |
---|
127 | |
---|
128 | async.select = function(cond, x){ |
---|
129 | // summary: |
---|
130 | // Executes a condition, waits for it if necessary, and executes |
---|
131 | // Nth function from list. |
---|
132 | var fs = opts.call(x) == "[object Array]" ? x : aps.call(arguments, 1); |
---|
133 | return function(init){ |
---|
134 | return new Deferred().addCallback(cond).addCallback(function(v){ |
---|
135 | if(typeof v == "number" && v >= 0 && v < fs.length){ |
---|
136 | return fs[v](init); |
---|
137 | }else{ |
---|
138 | return new Error("async.select: out of range"); |
---|
139 | } |
---|
140 | }).callback(init); |
---|
141 | }; |
---|
142 | }; |
---|
143 | |
---|
144 | async.ifThen = function(cond, ifTrue, ifFalse){ |
---|
145 | // summary: |
---|
146 | // Executes a condition, waits for it if necessary, and executes |
---|
147 | // one of two functions. |
---|
148 | return function(init){ |
---|
149 | return new Deferred().addCallback(cond).addCallback(function(v){ |
---|
150 | return (v ? ifTrue : ifFalse)(init); |
---|
151 | }).callback(init); |
---|
152 | }; |
---|
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 | /* |
---|
186 | Design decisions: |
---|
187 | |
---|
188 | seq() - behaves like the normal Deferred callback chain. |
---|
189 | |
---|
190 | par() - if error, all pending Deferreds are cancelled and the error is signaled, |
---|
191 | otherwise return an array of all results. |
---|
192 | |
---|
193 | any() - just like par() but only one result is returned. |
---|
194 | |
---|
195 | select() - any error is returned, otherwise the selected result is returned. |
---|
196 | |
---|
197 | loop() - any error is returned, otherwise the last result is returned. |
---|
198 | |
---|
199 | */ |
---|