Initial check-in
[dygraphs.git] / mochikit_v14 / doc / rst / MochiKit / Async.rst
1 .. title:: MochiKit.Async - manage asynchronous tasks
2
3 Name
4 ====
5
6 MochiKit.Async - manage asynchronous tasks
7
8
9 Synopsis
10 ========
11
12 ::
13
14     var url = "/src/b/bo/bob/MochiKit.Async/META.json";
15     /*
16
17         META.json looks something like this:
18
19         {"name": "MochiKit", "version": "0.5"}
20
21     */
22     var d = loadJSONDoc(url);
23     var gotMetadata = function (meta) {
24         if (MochiKit.Async.VERSION == meta.version) {
25             alert("You have the newest MochiKit.Async!");
26         } else {
27             alert("MochiKit.Async "
28                 + meta.version
29                 + " is available, upgrade!");
30         }
31     };
32     var metadataFetchFailed = function (err) {
33       alert("The metadata for MochiKit.Async could not be fetched :(");
34     };
35     d.addCallbacks(gotMetadata, metadataFetchFailed);
36
37
38 Description
39 ===========
40
41 MochiKit.Async provides facilities to manage asynchronous (as in AJAX
42 [1]_) tasks. The model for asynchronous computation used in this
43 module is heavily inspired by Twisted [2]_.
44
45
46 Dependencies
47 ============
48
49 - :mochiref:`MochiKit.Base`
50
51
52 Overview
53 ========
54
55 Deferred
56 --------
57
58 The Deferred constructor encapsulates a single value that is not
59 available yet. The most important example of this in the context of a
60 web browser would be an ``XMLHttpRequest`` to a server. The importance
61 of the Deferred is that it allows a consistent API to be exposed for
62 all asynchronous computations that occur exactly once.
63
64 The producer of the Deferred is responsible for doing all of the
65 complicated work behind the scenes. This often means waiting for a
66 timer to fire, or waiting for an event (e.g. ``onreadystatechange`` of
67 ``XMLHttpRequest``).  It could also be coordinating several events
68 (e.g.  ``XMLHttpRequest`` with a timeout, or several Deferreds
69 (e.g. fetching a set of XML documents that should be processed at the
70 same time).
71
72 Since these sorts of tasks do not respond immediately, the producer of
73 the Deferred does the following steps before returning to the
74 consumer:
75
76 1. Create a ``new`` :mochiref:`Deferred();` object and keep a
77    reference to it, because it will be needed later when the value is
78    ready.
79 2. Setup the conditions to create the value requested (e.g.  create a
80    new ``XMLHttpRequest``, set its ``onreadystatechange``).
81 3. Return the :mochiref:`Deferred` object.
82
83 Since the value is not yet ready, the consumer attaches a function to
84 the Deferred that will be called when the value is ready. This is not
85 unlike ``setTimeout``, or other similar facilities you may already be
86 familiar with.  The consumer can also attach an "errback" to the
87 :mochiref:`Deferred`, which is a callback for error handling.
88
89 When the value is ready, the producer simply calls
90 ``myDeferred.callback(theValue)``. If an error occurred, it should
91 call ``myDeferred.errback(theValue)`` instead.  As soon as this
92 happens, the callback that the consumer attached to the
93 :mochiref:`Deferred` is called with ``theValue`` as the only argument.
94
95 There are quite a few additional "advanced" features baked into
96 :mochiref:`Deferred`, such as cancellation and callback chains, so
97 take a look at the API reference if you would like to know more!
98
99 API Reference
100 =============
101
102 Errors
103 ------
104
105 :mochidef:`AlreadyCalledError`:
106
107     Thrown by a :mochiref:`Deferred` if ``.callback`` or ``.errback``
108     are called more than once.
109
110     *Availability*:
111         Available in MochiKit 1.3.1+
112
113
114 :mochidef:`BrowserComplianceError`:
115
116     Thrown when the JavaScript runtime is not capable of performing
117     the given function. Currently, this happens if the browser does
118     not support ``XMLHttpRequest``.
119
120     *Availability*:
121         Available in MochiKit 1.3.1+
122
123
124 :mochidef:`CancelledError`:
125
126     Thrown by a :mochiref:`Deferred` when it is cancelled, unless a
127     canceller is present and throws something else.
128
129     *Availability*:
130         Available in MochiKit 1.3.1+
131
132
133 :mochidef:`GenericError`:
134
135     Results passed to ``.fail`` or ``.errback`` of a
136     :mochiref:`Deferred` are wrapped by this ``Error`` if ``!(result
137     instanceof Error)``.
138
139     *Availability*:
140         Available in MochiKit 1.3.1+
141
142
143 :mochidef:`XMLHttpRequestError`:
144
145     Thrown when an ``XMLHttpRequest`` does not complete successfully
146     for any reason. The ``req`` property of the error is the failed
147     ``XMLHttpRequest`` object, and for convenience the ``number``
148     property corresponds to ``req.status``.
149
150     *Availability*:
151         Available in MochiKit 1.3.1+
152
153
154 Constructors
155 ------------
156
157 :mochidef:`Deferred()`:
158
159     Encapsulates a sequence of callbacks in response to a value that
160     may not yet be available. This is modeled after the Deferred class
161     from Twisted [3]_.
162
163 .. _`Twisted`: http://twistedmatrix.com/
164
165     Why do we want this?  JavaScript has no threads, and even if it
166     did, threads are hard. Deferreds are a way of abstracting
167     non-blocking events, such as the final response to an
168     ``XMLHttpRequest``.
169
170     The sequence of callbacks is internally represented as a list of
171     2-tuples containing the callback/errback pair. For example, the
172     following call sequence::
173
174         var d = new Deferred();
175         d.addCallback(myCallback);
176         d.addErrback(myErrback);
177         d.addBoth(myBoth);
178         d.addCallbacks(myCallback, myErrback);
179
180     is translated into a :mochiref:`Deferred` with the following
181     internal representation::
182
183         [
184             [myCallback, null],
185             [null, myErrback],
186             [myBoth, myBoth],
187             [myCallback, myErrback]
188         ]
189
190     The :mochiref:`Deferred` also keeps track of its current status
191     (fired).  Its status may be one of the following three values:
192
193
194         ===== ================================
195         Value Condition
196         ===== ================================
197         -1    no value yet (initial condition)
198         0     success
199         1     error
200         ===== ================================
201
202     A :mochiref:`Deferred` will be in the error state if one of the
203     following conditions are met:
204
205     1. The result given to callback or errback is "``instanceof
206        Error``"
207     2. The callback or errback threw while executing. If the thrown
208        object is not ``instanceof Error``, it will be wrapped with
209        :mochiref:`GenericError`.
210
211     Otherwise, the :mochiref:`Deferred` will be in the success
212     state. The state of the :mochiref:`Deferred` determines the next
213     element in the callback sequence to run.
214
215     When a callback or errback occurs with the example deferred chain,
216     something equivalent to the following will happen (imagine that
217     exceptions are caught and returned as-is)::
218
219         // d.callback(result) or d.errback(result)
220         if (!(result instanceof Error)) {
221             result = myCallback(result);
222         }
223         if (result instanceof Error) {
224             result = myErrback(result);
225         }
226         result = myBoth(result);
227         if (result instanceof Error) {
228             result = myErrback(result);
229         } else {
230             result = myCallback(result);
231         }
232
233     The result is then stored away in case another step is added to
234     the callback sequence. Since the :mochiref:`Deferred` already has
235     a value available, any new callbacks added will be called
236     immediately.
237
238     There are two other "advanced" details about this implementation
239     that are useful:
240
241     Callbacks are allowed to return :mochiref:`Deferred` instances, so
242     you can build complicated sequences of events with (relative)
243     ease.
244
245     The creator of the :mochiref:`Deferred` may specify a
246     canceller. The canceller is a function that will be called if
247     :mochiref:`Deferred.prototype.cancel` is called before the
248     :mochiref:`Deferred` fires. You can use this to allow an
249     ``XMLHttpRequest`` to be cleanly cancelled, for example. Note that
250     cancel will fire the :mochiref:`Deferred` with a
251     :mochiref:`CancelledError` (unless your canceller throws or
252     returns a different ``Error``), so errbacks should be prepared to
253     handle that ``Error`` gracefully for cancellable
254     :mochiref:`Deferred` instances.
255
256     *Availability*:
257         Available in MochiKit 1.3.1+
258
259
260 :mochidef:`Deferred.prototype.addBoth(func)`:
261
262     Add the same function as both a callback and an errback as the
263     next element on the callback sequence. This is useful for code
264     that you want to guarantee to run, e.g. a finalizer.
265
266     If additional arguments are given, then ``func`` will be replaced
267     with :mochiref:`MochiKit.Base.partial.apply(null,
268     arguments)`. This differs from `Twisted`_, because the result of
269     the callback or errback will be the *last* argument passed to
270     ``func``.
271
272     If ``func`` returns a :mochiref:`Deferred`, then it will be
273     chained (its value or error will be passed to the next
274     callback). Note that once the returned ``Deferred`` is chained, it
275     can no longer accept new callbacks.
276
277     *Availability*:
278         Available in MochiKit 1.3.1+
279
280
281 :mochidef:`Deferred.prototype.addCallback(func[, ...])`:
282
283     Add a single callback to the end of the callback sequence.
284
285     If additional arguments are given, then ``func`` will be replaced
286     with :mochiref:`MochiKit.Base.partial.apply(null,
287     arguments)`. This differs from `Twisted`_, because the result of
288     the callback will be the *last* argument passed to ``func``.
289
290     If ``func`` returns a :mochiref:`Deferred`, then it will be
291     chained (its value or error will be passed to the next
292     callback). Note that once the returned ``Deferred`` is chained, it
293     can no longer accept new callbacks.
294
295     *Availability*:
296         Available in MochiKit 1.3.1+
297
298
299 :mochidef:`Deferred.prototype.addCallbacks(callback, errback)`:
300
301     Add separate callback and errback to the end of the callback
302     sequence. Either callback or errback may be ``null``, but not
303     both.
304
305     If ``callback`` or ``errback`` returns a :mochiref:`Deferred`,
306     then it will be chained (its value or error will be passed to the
307     next callback). Note that once the returned ``Deferred`` is
308     chained, it can no longer accept new callbacks.
309
310     *Availability*:
311         Available in MochiKit 1.3.1+
312
313
314 :mochidef:`Deferred.prototype.addErrback(func)`:
315
316     Add a single errback to the end of the callback sequence.
317
318     If additional arguments are given, then ``func`` will be replaced
319     with :mochiref:`MochiKit.Base.partial.apply(null,
320     arguments)`. This differs from `Twisted`_, because the result of
321     the errback will be the *last* argument passed to ``func``.
322
323     If ``func`` returns a :mochiref:`Deferred`, then it will be
324     chained (its value or error will be passed to the next
325     callback). Note that once the returned ``Deferred`` is chained, it
326     can no longer accept new callbacks.
327
328     *Availability*:
329         Available in MochiKit 1.3.1+
330
331
332 :mochidef:`Deferred.prototype.callback([result])`:
333
334     Begin the callback sequence with a non-``Error`` result. Result
335     may be any value except for a :mochiref:`Deferred`.
336
337     Either ``.callback`` or ``.errback`` should be called exactly once
338     on a :mochiref:`Deferred`.
339
340     *Availability*:
341         Available in MochiKit 1.3.1+
342
343
344 :mochidef:`Deferred.prototype.cancel()`:
345
346     Cancels a :mochiref:`Deferred` that has not yet received a value,
347     or is waiting on another :mochiref:`Deferred` as its value.
348
349     If a canceller is defined, the canceller is called.  If the
350     canceller did not return an ``Error``, or there was no canceller,
351     then the errback chain is started with :mochiref:`CancelledError`.
352
353     *Availability*:
354         Available in MochiKit 1.3.1+
355
356
357 :mochidef:`Deferred.prototype.errback([result])`:
358
359     Begin the callback sequence with an error result.  Result may be
360     any value except for a :mochiref:`Deferred`, but if ``!(result
361     instanceof Error)``, it will be wrapped with
362     :mochiref:`GenericError`.
363
364     Either ``.callback`` or ``.errback`` should be called exactly once
365     on a :mochidef:`Deferred`.
366
367     *Availability*:
368         Available in MochiKit 1.3.1+
369
370
371 :mochidef:`DeferredLock()`:
372
373     A lock for asynchronous systems.
374
375     The ``locked`` property of a :mochiref:`DeferredLock` will be
376     ``true`` if it locked, ``false`` otherwise. Do not change this
377     property.
378
379     *Availability*:
380         Available in MochiKit 1.3.1+
381
382
383 :mochidef:`DeferredLock.prototype.acquire()`:
384
385     Attempt to acquire the lock. Returns a :mochiref:`Deferred` that
386     fires on lock acquisition with the :mochiref:`DeferredLock` as the
387     value.  If the lock is locked, then the :mochiref:`Deferred` goes
388     into a waiting list.
389
390     *Availability*:
391         Available in MochiKit 1.3.1+
392
393
394 :mochidef:`DeferredLock.prototype.release()`:
395
396     Release the lock. If there is a waiting list, then the first
397     :mochiref:`Deferred` in that waiting list will be called back.
398
399     *Availability*:
400         Available in MochiKit 1.3.1+
401
402
403 :mochidef:`DeferredList(list, [fireOnOneCallback, fireOnOneErrback, consumeErrors, canceller])`:
404
405     Combine a list of :mochiref:`Deferred` into one. Track the
406     callbacks and return a list of (success, result) tuples, 'success'
407     being a boolean indicating whether result is a normal result or an
408     error.
409
410     Once created, you have access to all :mochiref:`Deferred` methods,
411     like addCallback, addErrback, addBoth. The behaviour can be
412     changed by the following options:
413
414     ``fireOnOneCallback``:
415         Flag for launching the callback once the first Deferred of the
416         list has returned.
417
418     ``fireOnOneErrback``:
419         Flag for calling the errback at the first error of a Deferred.
420
421     ``consumeErrors``:
422         Flag indicating that any errors raised in the Deferreds should
423         be consumed by the DeferredList.
424
425     Example::
426
427         // We need to fetch data from 2 different urls
428         var d1 = loadJSONDoc(url1);
429         var d2 = loadJSONDoc(url2);
430         var l1 = new DeferredList([d1, d2], false, false, true);
431         l1.addCallback(function (resultList) {
432             MochiKit.Base.map(function (result) {
433                 if (result[0]) {
434                     alert("Data is here: " + result[1]);
435                 } else {
436                     alert("Got an error: " + result[1]);
437                 }
438             }, resultList);
439         });
440
441     *Availability*:
442         Available in MochiKit 1.3.1+
443
444
445 Functions
446 ---------
447
448 :mochidef:`callLater(seconds, func[, args...])`:
449
450     Call ``func(args...)`` after at least ``seconds`` seconds have
451     elapsed.  This is a convenience method for::
452
453         func = partial.apply(extend(null, arguments, 1));
454         return wait(seconds).addCallback(function (res) { return func() });
455
456     Returns a cancellable :mochiref:`Deferred`.
457
458     *Availability*:
459         Available in MochiKit 1.3.1+
460
461
462 :mochidef:`doXHR(url[, {option: value, ...}])`:
463
464     Perform a customized ``XMLHttpRequest`` and wrap it with a
465     :mochiref:`Deferred` that may be cancelled.
466
467     Note that only ``200`` (OK), ``201`` (CREATED),
468     ``204`` (NO CONTENT) and ``304`` (NOT MODIFIED) are considered
469     success codes. All other status codes will
470     result in an errback with an ``XMLHttpRequestError``.
471
472     ``url``:
473         The URL for this request.
474
475     The following options are currently accepted:
476
477     ``method``:
478         The HTTP method. Default is ``'GET'``.
479
480     ``sendContent``:
481         The content to send (e.g. with POST). Default is no content.
482
483     ``queryString``:
484         If present it will be used to build a query string to append to
485         the url using :mochiref:`MochiKit.Base.queryString`. Default is
486         no query string.
487
488     ``username``:
489         The username for the request. Default is no username.
490
491     ``password``:
492         The password for the request. Default is no password.
493
494     ``headers``:
495         Additional headers to set in the request, either as an object
496         such as ``{'Accept': 'text/xml'}`` or as an Array of 2-Arrays
497         ``[['Accept', 'text/xml']]``. Default is no additional headers.
498
499     ``mimeType``:
500         An override mime type. The typical use of this is to pass
501         'text/xml' to force XMLHttpRequest to attempt to parse responseXML.
502         Default is no override.
503
504     *returns*:
505         :mochiref:`Deferred` that will callback with the
506         ``XMLHttpRequest`` instance on success
507
508     *Availability*:
509         Available in MochiKit 1.4+.
510
511
512 :mochidef:`doSimpleXMLHttpRequest(url[, queryArguments...])`:
513
514     Perform a simple ``XMLHttpRequest`` and wrap it with a
515     :mochiref:`Deferred` that may be cancelled.
516
517     Note that only ``200`` (OK), ``201`` (CREATED),
518     ``204`` (NO CONTENT) and ``304`` (NOT MODIFIED) are considered
519     success codes. All other status codes will
520     result in an errback with an ``XMLHttpRequestError``.
521
522     ``url``:
523         The URL to GET
524
525     ``queryArguments``:
526         If this function is called with more than one argument, a
527         ``"?"`` and the result of
528         :mochiref:`MochiKit.Base.queryString` with the rest of the
529         arguments are appended to the URL.
530
531         For example, this will do a GET request to the URL
532         ``http://example.com?bar=baz``::
533
534             doSimpleXMLHttpRequest("http://example.com", {bar: "baz"});
535
536     *returns*:
537         :mochiref:`Deferred` that will callback with the
538         ``XMLHttpRequest`` instance on success
539
540     *Availability*:
541         Available in MochiKit 1.3.1+. Support for 201 and 204 were added in
542         MochiKit 1.4.
543
544
545 :mochidef:`evalJSONRequest(req)`:
546
547     Evaluate a JSON [4]_ ``XMLHttpRequest``
548
549     ``req``:
550         The request whose ``.responseText`` property is to be
551         evaluated
552
553     *returns*:
554         A JavaScript object
555
556     *Availability*:
557         Available in MochiKit 1.3.1+
558
559
560 :mochidef:`fail([result])`:
561
562     Return a :mochiref:`Deferred` that has already had
563     ``.errback(result)`` called.
564
565     See ``succeed`` documentation for rationale.
566
567     ``result``:
568         The result to give to
569         :mochiref:`Deferred.prototype.errback(result)`.
570
571     *returns*:
572         A ``new`` :mochiref:`Deferred()`
573
574     *Availability*:
575         Available in MochiKit 1.3.1+
576
577
578 :mochidef:`gatherResults(deferreds)`:
579
580     A convenience function that returns a :mochiref:`DeferredList`
581     from the given ``Array`` of :mochiref:`Deferred` instances that
582     will callback with an ``Array`` of just results when they're
583     available, or errback on the first array.
584
585     *Availability*:
586         Available in MochiKit 1.3.1+
587
588
589 :mochidef:`getXMLHttpRequest()`:
590
591     Return an ``XMLHttpRequest`` compliant object for the current
592     platform.
593
594     In order of preference:
595
596     - ``new XMLHttpRequest()``
597     - ``new ActiveXObject('Msxml2.XMLHTTP')``
598     - ``new ActiveXObject('Microsoft.XMLHTTP')``
599     - ``new ActiveXObject('Msxml2.XMLHTTP.4.0')``
600
601     *Availability*:
602         Available in MochiKit 1.3.1+
603
604
605 :mochidef:`maybeDeferred(func[, argument...])`:
606
607     Call a ``func`` with the given arguments and ensure the result is
608     a :mochiref:`Deferred`.
609
610     ``func``:
611         The function to call.
612
613     *returns*:
614         A new :mochiref:`Deferred` based on the call to ``func``. If
615         ``func`` does not naturally return a :mochiref:`Deferred`, its
616         result or error value will be wrapped by one.
617
618     *Availability*:
619         Available in MochiKit 1.3.1+
620
621
622 :mochidef:`loadJSONDoc(url[, queryArguments...])`:
623
624     Do a simple ``XMLHttpRequest`` to a URL and get the response as a
625     JSON [4]_ document.
626
627     ``url``:
628         The URL to GET
629
630     ``queryArguments``:
631         If this function is called with more than one argument, a
632         ``"?"`` and the result of
633         :mochiref:`MochiKit.Base.queryString` with the rest of the
634         arguments are appended to the URL.
635
636         For example, this will do a GET request to the URL
637         ``http://example.com?bar=baz``::
638
639             loadJSONDoc("http://example.com", {bar: "baz"});
640
641     *returns*:
642         :mochiref:`Deferred` that will callback with the evaluated
643         JSON [4]_ response upon successful ``XMLHttpRequest``
644
645     *Availability*:
646         Available in MochiKit 1.3.1+
647
648
649 :mochidef:`sendXMLHttpRequest(req[, sendContent])`:
650
651     Set an ``onreadystatechange`` handler on an ``XMLHttpRequest``
652     object and send it off. Will return a cancellable
653     :mochiref:`Deferred` that will callback on success.
654
655     Note that only ``200`` (OK), ``201`` (CREATED),
656     ``204`` (NO CONTENT) and ``304`` (NOT MODIFIED) are considered
657     success codes. All other status codes will
658     result in an errback with an ``XMLHttpRequestError``.
659
660     ``req``:
661         An preconfigured ``XMLHttpRequest`` object (open has been
662         called).
663
664     ``sendContent``:
665         Optional string or DOM content to send over the
666         ``XMLHttpRequest``.
667
668     *returns*:
669         :mochiref:`Deferred` that will callback with the
670         ``XMLHttpRequest`` instance on success.
671
672     *Availability*:
673         Available in MochiKit 1.3.1+. Support for 201 and 204 were added in
674         MochiKit 1.4.
675
676
677 :mochidef:`succeed([result])`:
678
679     Return a :mochiref:`Deferred` that has already had
680     ``.callback(result)`` called.
681
682     This is useful when you're writing synchronous code to an
683     asynchronous interface: i.e., some code is calling you expecting a
684     :mochiref:`Deferred` result, but you don't actually need to do
685     anything asynchronous. Just return ``succeed(theResult)``.
686
687     See ``fail`` for a version of this function that uses a failing
688     :mochiref:`Deferred` rather than a successful one.
689
690     ``result``:
691         The result to give to
692         :mochiref:`Deferred.prototype.callback(result)`
693
694     *returns*:
695         a ``new`` :mochiref:`Deferred`
696
697     *Availability*:
698         Available in MochiKit 1.3.1+
699
700
701 :mochidef:`wait(seconds[, res])`:
702
703     Return a new cancellable :mochiref:`Deferred` that will
704     ``.callback(res)`` after at least ``seconds`` seconds have
705     elapsed.
706
707     *Availability*:
708         Available in MochiKit 1.3.1+
709
710
711 See Also
712 ========
713
714 .. [1] AJAX, Asynchronous JavaScript and XML: http://en.wikipedia.org/wiki/AJAX
715 .. [2] Twisted, an event-driven networking framework written in Python: http://twistedmatrix.com/
716 .. [3] Twisted Deferred Reference: http://twistedmatrix.com/projects/core/documentation/howto/defer.html
717 .. [4] JSON, JavaScript Object Notation: http://json.org/
718
719
720 Authors
721 =======
722
723 - Bob Ippolito <bob@redivi.com>
724
725
726 Copyright
727 =========
728
729 Copyright 2005 Bob Ippolito <bob@redivi.com>. This program is
730 dual-licensed free software; you can redistribute it and/or modify it
731 under the terms of the `MIT License`_ or the `Academic Free License
732 v2.1`_.
733
734 .. _`MIT License`: http://www.opensource.org/licenses/mit-license.php
735 .. _`Academic Free License v2.1`: http://www.opensource.org/licenses/afl-2.1.php