1 .. title:: MochiKit.Async - manage asynchronous tasks
6 MochiKit.Async - manage asynchronous tasks
14 var url = "/src/b/bo/bob/MochiKit.Async/META.json";
17 META.json looks something like this:
19 {"name": "MochiKit", "version": "0.5"}
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!");
27 alert("MochiKit.Async "
29 + " is available, upgrade!");
32 var metadataFetchFailed = function (err) {
33 alert("The metadata for MochiKit.Async could not be fetched :(");
35 d.addCallbacks(gotMetadata, metadataFetchFailed);
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]_.
49 - :mochiref:`MochiKit.Base`
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.
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
72 Since these sorts of tasks do not respond immediately, the producer of
73 the Deferred does the following steps before returning to the
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
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.
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.
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.
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!
105 :mochidef:`AlreadyCalledError`:
107 Thrown by a :mochiref:`Deferred` if ``.callback`` or ``.errback``
108 are called more than once.
111 Available in MochiKit 1.3.1+
114 :mochidef:`BrowserComplianceError`:
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``.
121 Available in MochiKit 1.3.1+
124 :mochidef:`CancelledError`:
126 Thrown by a :mochiref:`Deferred` when it is cancelled, unless a
127 canceller is present and throws something else.
130 Available in MochiKit 1.3.1+
133 :mochidef:`GenericError`:
135 Results passed to ``.fail`` or ``.errback`` of a
136 :mochiref:`Deferred` are wrapped by this ``Error`` if ``!(result
140 Available in MochiKit 1.3.1+
143 :mochidef:`XMLHttpRequestError`:
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``.
151 Available in MochiKit 1.3.1+
157 :mochidef:`Deferred()`:
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
163 .. _`Twisted`: http://twistedmatrix.com/
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
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::
174 var d = new Deferred();
175 d.addCallback(myCallback);
176 d.addErrback(myErrback);
178 d.addCallbacks(myCallback, myErrback);
180 is translated into a :mochiref:`Deferred` with the following
181 internal representation::
187 [myCallback, myErrback]
190 The :mochiref:`Deferred` also keeps track of its current status
191 (fired). Its status may be one of the following three values:
194 ===== ================================
196 ===== ================================
197 -1 no value yet (initial condition)
200 ===== ================================
202 A :mochiref:`Deferred` will be in the error state if one of the
203 following conditions are met:
205 1. The result given to callback or errback is "``instanceof
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`.
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.
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)::
219 // d.callback(result) or d.errback(result)
220 if (!(result instanceof Error)) {
221 result = myCallback(result);
223 if (result instanceof Error) {
224 result = myErrback(result);
226 result = myBoth(result);
227 if (result instanceof Error) {
228 result = myErrback(result);
230 result = myCallback(result);
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
238 There are two other "advanced" details about this implementation
241 Callbacks are allowed to return :mochiref:`Deferred` instances, so
242 you can build complicated sequences of events with (relative)
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.
257 Available in MochiKit 1.3.1+
260 :mochidef:`Deferred.prototype.addBoth(func)`:
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.
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
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.
278 Available in MochiKit 1.3.1+
281 :mochidef:`Deferred.prototype.addCallback(func[, ...])`:
283 Add a single callback to the end of the callback sequence.
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``.
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.
296 Available in MochiKit 1.3.1+
299 :mochidef:`Deferred.prototype.addCallbacks(callback, errback)`:
301 Add separate callback and errback to the end of the callback
302 sequence. Either callback or errback may be ``null``, but not
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.
311 Available in MochiKit 1.3.1+
314 :mochidef:`Deferred.prototype.addErrback(func)`:
316 Add a single errback to the end of the callback sequence.
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``.
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.
329 Available in MochiKit 1.3.1+
332 :mochidef:`Deferred.prototype.callback([result])`:
334 Begin the callback sequence with a non-``Error`` result. Result
335 may be any value except for a :mochiref:`Deferred`.
337 Either ``.callback`` or ``.errback`` should be called exactly once
338 on a :mochiref:`Deferred`.
341 Available in MochiKit 1.3.1+
344 :mochidef:`Deferred.prototype.cancel()`:
346 Cancels a :mochiref:`Deferred` that has not yet received a value,
347 or is waiting on another :mochiref:`Deferred` as its value.
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`.
354 Available in MochiKit 1.3.1+
357 :mochidef:`Deferred.prototype.errback([result])`:
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`.
364 Either ``.callback`` or ``.errback`` should be called exactly once
365 on a :mochidef:`Deferred`.
368 Available in MochiKit 1.3.1+
371 :mochidef:`DeferredLock()`:
373 A lock for asynchronous systems.
375 The ``locked`` property of a :mochiref:`DeferredLock` will be
376 ``true`` if it locked, ``false`` otherwise. Do not change this
380 Available in MochiKit 1.3.1+
383 :mochidef:`DeferredLock.prototype.acquire()`:
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
391 Available in MochiKit 1.3.1+
394 :mochidef:`DeferredLock.prototype.release()`:
396 Release the lock. If there is a waiting list, then the first
397 :mochiref:`Deferred` in that waiting list will be called back.
400 Available in MochiKit 1.3.1+
403 :mochidef:`DeferredList(list, [fireOnOneCallback, fireOnOneErrback, consumeErrors, canceller])`:
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
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:
414 ``fireOnOneCallback``:
415 Flag for launching the callback once the first Deferred of the
418 ``fireOnOneErrback``:
419 Flag for calling the errback at the first error of a Deferred.
422 Flag indicating that any errors raised in the Deferreds should
423 be consumed by the DeferredList.
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) {
434 alert("Data is here: " + result[1]);
436 alert("Got an error: " + result[1]);
442 Available in MochiKit 1.3.1+
448 :mochidef:`callLater(seconds, func[, args...])`:
450 Call ``func(args...)`` after at least ``seconds`` seconds have
451 elapsed. This is a convenience method for::
453 func = partial.apply(extend(null, arguments, 1));
454 return wait(seconds).addCallback(function (res) { return func() });
456 Returns a cancellable :mochiref:`Deferred`.
459 Available in MochiKit 1.3.1+
462 :mochidef:`doXHR(url[, {option: value, ...}])`:
464 Perform a customized ``XMLHttpRequest`` and wrap it with a
465 :mochiref:`Deferred` that may be cancelled.
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``.
473 The URL for this request.
475 The following options are currently accepted:
478 The HTTP method. Default is ``'GET'``.
481 The content to send (e.g. with POST). Default is no content.
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
489 The username for the request. Default is no username.
492 The password for the request. Default is no password.
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.
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.
505 :mochiref:`Deferred` that will callback with the
506 ``XMLHttpRequest`` instance on success
509 Available in MochiKit 1.4+.
512 :mochidef:`doSimpleXMLHttpRequest(url[, queryArguments...])`:
514 Perform a simple ``XMLHttpRequest`` and wrap it with a
515 :mochiref:`Deferred` that may be cancelled.
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``.
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.
531 For example, this will do a GET request to the URL
532 ``http://example.com?bar=baz``::
534 doSimpleXMLHttpRequest("http://example.com", {bar: "baz"});
537 :mochiref:`Deferred` that will callback with the
538 ``XMLHttpRequest`` instance on success
541 Available in MochiKit 1.3.1+. Support for 201 and 204 were added in
545 :mochidef:`evalJSONRequest(req)`:
547 Evaluate a JSON [4]_ ``XMLHttpRequest``
550 The request whose ``.responseText`` property is to be
557 Available in MochiKit 1.3.1+
560 :mochidef:`fail([result])`:
562 Return a :mochiref:`Deferred` that has already had
563 ``.errback(result)`` called.
565 See ``succeed`` documentation for rationale.
568 The result to give to
569 :mochiref:`Deferred.prototype.errback(result)`.
572 A ``new`` :mochiref:`Deferred()`
575 Available in MochiKit 1.3.1+
578 :mochidef:`gatherResults(deferreds)`:
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.
586 Available in MochiKit 1.3.1+
589 :mochidef:`getXMLHttpRequest()`:
591 Return an ``XMLHttpRequest`` compliant object for the current
594 In order of preference:
596 - ``new XMLHttpRequest()``
597 - ``new ActiveXObject('Msxml2.XMLHTTP')``
598 - ``new ActiveXObject('Microsoft.XMLHTTP')``
599 - ``new ActiveXObject('Msxml2.XMLHTTP.4.0')``
602 Available in MochiKit 1.3.1+
605 :mochidef:`maybeDeferred(func[, argument...])`:
607 Call a ``func`` with the given arguments and ensure the result is
608 a :mochiref:`Deferred`.
611 The function to call.
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.
619 Available in MochiKit 1.3.1+
622 :mochidef:`loadJSONDoc(url[, queryArguments...])`:
624 Do a simple ``XMLHttpRequest`` to a URL and get the response as a
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.
636 For example, this will do a GET request to the URL
637 ``http://example.com?bar=baz``::
639 loadJSONDoc("http://example.com", {bar: "baz"});
642 :mochiref:`Deferred` that will callback with the evaluated
643 JSON [4]_ response upon successful ``XMLHttpRequest``
646 Available in MochiKit 1.3.1+
649 :mochidef:`sendXMLHttpRequest(req[, sendContent])`:
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.
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``.
661 An preconfigured ``XMLHttpRequest`` object (open has been
665 Optional string or DOM content to send over the
669 :mochiref:`Deferred` that will callback with the
670 ``XMLHttpRequest`` instance on success.
673 Available in MochiKit 1.3.1+. Support for 201 and 204 were added in
677 :mochidef:`succeed([result])`:
679 Return a :mochiref:`Deferred` that has already had
680 ``.callback(result)`` called.
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)``.
687 See ``fail`` for a version of this function that uses a failing
688 :mochiref:`Deferred` rather than a successful one.
691 The result to give to
692 :mochiref:`Deferred.prototype.callback(result)`
695 a ``new`` :mochiref:`Deferred`
698 Available in MochiKit 1.3.1+
701 :mochidef:`wait(seconds[, res])`:
703 Return a new cancellable :mochiref:`Deferred` that will
704 ``.callback(res)`` after at least ``seconds`` seconds have
708 Available in MochiKit 1.3.1+
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/
723 - Bob Ippolito <bob@redivi.com>
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
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