1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith<div class="intro" class="component">
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith AsyncQueue allows you create a chain of function callbacks executed via
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <code>setTimeout</code> that are guaranteed to run in order. This can
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith enable progressive incremental rendering of your UI so your users can
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith begin to see and interact with your page while the infrastructure is
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith being built. Similarly, process-intensive operations that will lock up
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith the UI while the JavaScript is being executed can be broken up into
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith chunks, helping to keep your interface responsive.
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith{{>getting-started}}
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith<h2 id="using">Using AsyncQueue</h2>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith<h3 id="interacting">Creating and interacting with an AsyncQueue</h3>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith AsyncQueues manage an array of callbacks that can be either simple function
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith references or <a href="#callbacks">objects with specific keys</a>. The
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith primary methods on AsyncQueue are <code>add</code> and
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <code>run</code>.
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith When <code>run()</code> is invoked, each callback is executed in turn,
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith either synchronously or via <code>setTimeout</code> (depending on the
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith configuration of the callback or of the AsyncQueue instance).
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith Queued callbacks can also be promoted to the top of the queue or removed
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smithvar q = new Y.AsyncQueue(callbackB, someTask, callbackA, callbackC);
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smithq.add(callbackD, callbackE); // B, someTask, A, C, D, E
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smithq.promote(callbackA); // A, B, someTask, C, D, E
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smithq.remove(someTask); // A, B, C, D, E
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smithq.run(); // execute A, then B, then C, then D, then E
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith<h4 id="stopping">Pausing and stopping an AsyncQueue</h4>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith In addition to <code>run()</code>, AsyncQueue instances also have
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <code>pause()</code> and <code>stop()</code> methods to interrupt the run
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith To wait for an external process to complete, such as an XHR request, call
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <code>pause()</code>, then <code>run()</code> again to resume
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith Call <code>stop()</code> to terminate execution and flush the AsyncQueue.
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith// Seed the instance with callbacks
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith // The second callback will pause the Queue and send an XHR for data
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith function () {
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith // Send the asynchronous XHR
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith success : function (xid,o) {
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith // In the XHR callback, restart the AsyncQueue if successful
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith failure : function () {
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith // Stop the AsyncQueue if anything goes wrong
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith // The third callback will do partial updates until complete
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith until: function () {
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith<h4 id="callbacks">About AsyncQueue callbacks</h4>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith AsyncQueue callbacks can be simple function references or object literals
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith with the following keys:
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <th>property</th>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <th>description</th>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <th>default</th>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td><code>fn</code></td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td><strong>Required</strong>. The callback function to execute.</td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td>(none)</td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td><code>context</code></td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td>The context from which to execute the callback function.</td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td>The AsyncQueue instance</td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td><code>args</code></td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td>Array of arguments that will be passed as individual args to the callback function.</td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td>(none)</td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td><code>timeout</code></td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td>Millisecond delay before each execution of this callback. Set to -1 to trigger synchronous execution.</td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td><code>iterations</code></td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td>The number of times to execute this callback before shifting it from the queue.</td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td><code>until</code></td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td>A function that will return <code>true</code> when the current callback can be shifted from the queue.</td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td>a function that tests against <code>iterations</code></td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td><code>id</code></td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td>Name given to this callback for ease of reference.</td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td>(none)</td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td><code>autoContinue</code></td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td>Set to <code>false</code> to automatically <code>pause()</code> after this callback.</td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td>true</td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith<h4 id="defaults">Class- and instance-level callback defaults</h4>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith AsyncQueue provides three places to configure callbacks (in decreasing
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith precedence order):
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <li>The callback object</li>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <li>The AsyncQueue instance's <code>defaults</code> collection</li>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <li>The class static <code>defaults</code> collection</li>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith// All AsyncQueue instances will execute all callbacks synchronously by default
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith// run every callback in this instance twice before moving to the next callback
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith fn: functionB,
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith timeout: 100 // this callback will be executed asynchronously
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith// functionA executes twice immediately, then after 100 milliseconds functionB
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith// is executed, then after another 100ms functionB is executed again.
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith<h4 id="sync">Synchronous mode for callback execution</h4>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith One of the main goals of the AsyncQueue is to provide a mechanism to
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith prevent process-intensive operations from locking up the UI. By default,
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith AsyncQueue callbacks are executed via <code>setTimeout</code> to facilitate
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith this. The <code>timeout</code> configuration accepts -1 as a value to
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith trigger synchronous callback execution. Use this setting with caution.
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith<h4 id="chaining">About timeout chaining</h4>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith Timeout chaining is a strategy to address the lack of <a
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith href="http://en.wikipedia.org/wiki/Thread_(computer_science)">multithreading</a>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith in JavaScript. When complex or iterative code executes it can cause the
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith page to stop responding until the running JavaScript process completes; it
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith can also cause "non-responsive script" or "long-running script" dialogs to
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith be presented to the user. Both outcomes are detrimental to user
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith To address this, the operation can be split into chunks, and
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <code>setTimeout</code> can be used to yield control back to other
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith operations between each chunk. A common use case for this technique is to
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith allow browser reflows to display DOM modifications incrementally while
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith batches of work are being done in JavaScript. For iterative functions, the
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith code can execute a portion of the overall work, then schedule itself to run
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith via <code>setTimeout</code>.
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith<p>The basic form of an iterative timeout chain is:</p>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith(function () {
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith /* do a chunk of the work */
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith if (/* process completion check fails */) {
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith // Schedule myself for re-execution, picking up where I left off
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith When dealing with <code>setTimeout</code>, it's easy to introduce race
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith conditions. Because all timeouts are scheduled against the same timer and
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith only one can run at a time, when two timeouts are separately scheduled, it
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith is possible for them to execute out of intended order.
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith AsyncQueue supports both "chunked operations" (by specifying callback
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith timeouts) and "iterative operations" (by specifying callback
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <code>iterations</code> or <code>until</code> functions). Furthermore,
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith AsyncQueue manages the callback sequence and can therefore guarantee the
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith execution order, so you avoid race conditions.
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith<h4 id="events">Exposed events</h4>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith AsyncQueue is based on EventTarget and instances emit the following events
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith throughout their lifecycle:
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <th>Event</th>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <th>When</th>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <th>Event payload</th>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td><code>add</code></td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td>Callbacks are added to the AsyncQueue.</td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td><code>{ callbacks: (Array of callbacks added) }</code></td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td><code>promote</code></td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td>A callback is promoted.</td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td><code>{ callback : (callback) }</code></td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td><code>remove</code></td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td>A callback is removed.</td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td><code>{ callback : (callback) }</code></td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td><code>execute</code></td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td>A callback is executed.</td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td><code>{ callback : (callback) }</code></td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td><code>shift</code></td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td>A callback is shifted from the AsyncQueue.</td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td><code>{ callback : (callback) }</code></td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td><code>complete</code></td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td>After the last callback is finished executing. <em>NOT</em> fired after <code>stop()</code>.</td>
249e4018d7634fb9dc0c49976e034993f8fa065cLuke Smith <td>(none)</td>