Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(35)

Unified Diff: sdk/lib/async/future.dart

Issue 11852027: Improve documentation for futures. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Replace [:...:] with backquotes. Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sdk/lib/async/future.dart
diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
index 139f34c6f14062cd787fd6b5df2e6ff29238dc7a..0c4daa0895577b9b0049396ad92f6ee1cecb523f 100644
--- a/sdk/lib/async/future.dart
+++ b/sdk/lib/async/future.dart
@@ -5,33 +5,97 @@
part of dart.async;
/**
- * A [Future] is used to obtain a value sometime in the future. Receivers of a
- * [Future] can obtain the value by passing a callback to [then]. For example:
+ * A [Future] represents a delayed computation. It is used to obtain a not-yet
+ * available value, or error, sometime in the future. Receivers of a
+ * [Future] can register callbacks that handle the value or error once it is
+ * available. For example:
*
- * Future<int> future = getFutureFromSomewhere();
- * future.then((value) {
- * print("I received the number $value");
+ * Future<int> future = getFuture();
+ * future.then((value) => handleValue(value))
+ * .catchError((error) => handleError(error));
+ *
+ * A [Future] can be completed in two ways: with a value ("the future succeeds")
+ * or with an error ("the future fails"). Users can install callbacks for each
+ * case. The result of registering a pair of callbacks is a new Future (the
+ * "successor") which in turn is completed with the result of invoking the
+ * corresponding callback. The successor is completed with an error if the
+ * invoked callback throws. For example:
+ *
+ * Future<int> successor = future.then((int value) {
+ * // Invoked when the future is completed with a value.
+ * return 42; // The successor is completed with the value 42.
+ * },
+ * onError: (AsyncError e) {
+ * // Invoked when the future is completed with an error.
+ * if (canHandle(e)) {
+ * return 499; // The successor is completed with the value 499.
+ * } else {
+ * throw e; // The successor is completed with the error e.
+ * }
+ * });
+ *
+ * If a future does not have a successor but is completed with an error, it
+ * forwards the error message to the global error-handler. This special casing
+ * makes sure that no error is silently dropped. However, it also means that
+ * error handlers should be installed early, so that they are present as soon
+ * as a future is completed with an error. The following example demonstrates
+ * this potential bug:
+ *
+ * var future = getFuture();
+ * new Timer(5, (_) {
+ * // The error-handler is only attached 5ms after the future has been
+ * // received. If the future fails in the mean-time it will forward the
+ * // error to the global error-handler, even though there is code (just
+ * // below) to handle the error.
+ * future.then((value) { useValue(value); },
+ * onError: (e) { handleError(e); });
* });
*
- * A future may complete by *succeeding* (producing a value) or *failing*
- * (producing an error, which may be handled with [catchError]).
+ * In general we discourage registering the two callbacks at the same time, but
+ * prefer to use [then] with one argument (the value handler), and to use
+ * [catchError] for handling errors. The missing callbacks (the error-handler
+ * for [then], and the value-handler for [catchError]), are automatically
+ * configured to "forward" the value/error. Separating value and error-handling
+ * into separate registration calls usually leads to code that is easier to
+ * reason about. In fact it makes asynchronous code very similar to synchronous
+ * code:
+ *
+ * // Synchronous code.
+ * try {
+ * int value = foo();
+ * return bar(value);
+ * } catch (e) {
+ * return 499;
+ * }
+ *
+ * Equivalent asynchronous code, based on futures:
*
- * When a future completes, the following actions happen in order:
+ * Future<int> future = foo(); // foo now returns a future.
+ * future.then((int value) => bar(value))
+ * .catchError((e) => 499);
*
- * 1. if the future suceeded, handlers registered with [then] are called.
- * 2. if the future failed, handlers registered with [catchError] are
- * tested in sequence. Each test returning true is, have its handler
- * called.
- * 4. if the future failed, and no handler registered with [catchError] it
- * is accepting the error, an error is sent to the global error handler.
+ * Similar to the synchronous code, the error handler (registered with
+ * [catchError]) is handling the errors for exceptions coming from calls to
+ * 'foo', as well as 'bar'. This would not be the case if the error-handler was
+ * registered at the same time as the value-handler.
*
- * [Future]s are usually not created directly, but with [Completer]s.
+ * Futures can have more than one callback-pairs registered. Each successor is
+ * treated independently and is handled as if it was the only successor.
*/
+// TODO(floitsch): document chaining.
abstract class Future<T> {
- /** A future whose value is immediately available. */
+ /**
+ * A future whose value is available in the next event-loop iteration.
+ *
+ * See [Completer]s, for futures with values that are computed asynchronously.
+ */
factory Future.immediate(T value) => new _FutureImpl<T>.immediate(value);
- /** A future that completes with an error. */
+ /**
+ * A future that completes with an error in the next event-loop iteration.
+ *
+ * See [Completer]s, for futures with values that are computed asynchronously.
+ */
factory Future.immediateError(var error, [Object stackTrace]) {
return new _FutureImpl<T>.immediateError(error, stackTrace);
}
@@ -40,10 +104,13 @@ abstract class Future<T> {
* Creates a future that completes after a delay.
*
* The future will be completed after [milliseconds] have passed with
- * the result of calling [value].
+ * the result of calling [value]. If [milliseconds] is 0, it completes at the
+ * earliest in the next event-loop iteration.
*
* If calling [value] throws, the created future will complete with the
* error.
+ *
+ * See [Completer]s, for futures with values that are computed asynchronously.
*/
factory Future.delayed(int milliseconds, T value()) {
_FutureImpl<T> future = new _ThenFuture<dynamic, T>((_) => value());
@@ -55,8 +122,8 @@ abstract class Future<T> {
* Wait for all the given futures to complete and collect their values.
*
* Returns a future which will complete once all the futures in a list are
- * complete. If any of the futures in the list completes with an exception,
- * the resulting future also completes with an exception. Otherwise the value
+ * complete. If any of the futures in the list completes with an error,
+ * the resulting future also completes with an error. Otherwise the value
* of the returned future will be a list of all the values that were produced.
*/
static Future<List> wait(Iterable<Future> futures) {
@@ -92,27 +159,23 @@ abstract class Future<T> {
* value. If [this] future is already completed then the invocation of
* [onValue] is delayed until the next event-loop iteration.
*
- * Returns a new [Future] [:f:].
- *
- * If [this] is completed with an error then [:f:] is completed with the same
- * error. If [this] is completed with a value, then [:f:]'s completion value
- * depends on the result of invoking [onValue] with [this]' completion value.
+ * Returns a new [Future] `f` which is completed with the result of
+ * invoking [onValue] (if [this] completes with a value) or [onError] (if
+ * [this] completes with an error).
*
- * If [onValue] returns a [Future] [:f2:] then [:f:] and [:f2:] are chained.
- * That is, [:f:] is completed with the completion value of [:f2:].
+ * If the invoked callback throws an exception, the returned future `f` is
+ * completed with the error. If the value thrown is an [AsyncError], it is
+ * used directly, as the error result. Otherwise it is wrapped in an
+ * [AsyncError] first.
*
- * Otherwise [:f:] is completed with the return value of [onValue].
+ * If the invoked callback returns a [Future] `f2` then `f` and `f2` are
+ * chained. That is, `f` is completed with the completion value of `f2`.
*
- * If [onValue] throws an exception, the returned future will receive the
- * exception. If the value thrown is an [AsyncError], it is used directly,
- * as the error result, otherwise it is wrapped in an [AsyncError] first.
- *
- * If [onError] is provided, it is called if this future completes with an
- * error, and its return value/throw behavior is handled the same way as
- * for [catchError] without a [:test:] argument.
+ * If [onError] is not given, it is equivalent to `(e) { throw e; }`. That
+ * is, it forwards the error to `f`.
*
* In most cases, it is more readable to use [catchError] separately, possibly
- * with a [:test:] parameter, instead of handling both value and error in a
+ * with a `test` parameter, instead of handling both value and error in a
* single [then] call.
*/
Future then(onValue(T value), { onError(AsyncError asyncError) });
@@ -120,23 +183,42 @@ abstract class Future<T> {
/**
* Handles errors emitted by this [Future].
*
- * When this future completes with an error, first [test] is called with the
- * error's value.
+ * Returns a new [Future] `f`.
+ *
+ * When [this] completes with a value, the value is forwarded to `f`
+ * unmodified. That is, `f` completes with the same value.
*
- * If [test] returns [true], [onError] is called with the error
- * wrapped in an [AsyncError]. The result of [onError] is handled exactly as
- * [then]'s [onValue].
+ * When [this] completes with an error, [test] is called with the
+ * error's value. If the invocation returns [true], [onError] is called with
+ * the error wrapped in an [AsyncError]. The result of [onError] is handled
+ * exactly the same as for [then]'s [onError].
*
* If [test] returns false, the exception is not handled by [onError], but is
- * emitted by the returned Future unmodified.
+ * thrown unmodified, thus forwarding it to `f`.
*
* If [test] is omitted, it defaults to a function that always returns true.
*
* Example:
- * foo
- * .catchError(..., test: (e) => e is ArgumentError)
- * .catchError(..., test: (e) => e is NoSuchMethodError)
- * .then((v) { ... });
+ *
+ * foo
+ * .catchError(..., test: (e) => e is ArgumentError)
+ * .catchError(..., test: (e) => e is NoSuchMethodError)
+ * .then((v) { ... });
+ *
+ * This method is equivalent to:
+ *
+ * Future catchError(onError(AsyncError asyncError),
+ * {bool test(Object error)}) {
+ * this.then((v) => v, // Forward the value.
+ * // But handle errors, if the [test] succeeds.
+ * onError: (AsyncError e) {
+ * if (test == null || test(e.error)) {
+ * return onError(e);
+ * }
+ * throw e;
+ * });
+ * }
+ *
*/
Future catchError(onError(AsyncError asyncError),
{bool test(Object error)});
@@ -149,17 +231,30 @@ abstract class Future<T> {
*
* This is the asynchronous equivalent of a "finally" block.
*
- * The future returned by this call, [:f:], will complete the same way
+ * The future returned by this call, `f`, will complete the same way
* as this future unless an error occurs in the [action] call, or in
* a [Future] returned by the [action] call. If the call to [action]
* does not return a future, its return value is ignored.
*
- * If the call to [action] throws, then [:f:] is completed with the
+ * If the call to [action] throws, then `f` is completed with the
* thrown error.
*
- * If the call to [action] returns a [Future], [:f2:], then completion of
- * [:f:] is delayed until [:f2:] completes. If [:f2:] completes with
- * an error, that will be the result of [:f:] too.
+ * If the call to [action] returns a [Future], `f2`, then completion of
+ * `f` is delayed until `f2` completes. If `f2` completes with
+ * an error, that will be the result of `f` too.
+ *
+ * This method is equivalent to:
+ *
+ * Future<T> whenComplete(action()) {
+ * this.then((v) {
+ * action();
+ * return v
+ * },
+ * onError: (AsyncError e) {
+ * action();
+ * throw e;
+ * });
+ * }
*/
Future<T> whenComplete(action());
@@ -210,7 +305,7 @@ abstract class Completer<T> {
* Completing a future with an error indicates that an exception was thrown
* while trying to produce a value.
*
- * The argument [exception] should not be [:null:].
+ * The argument [exception] should not be `null`.
*
* If [exception] is an [AsyncError], it is used directly as the error
* message sent to the future's listeners, and [stackTrace] is ignored.
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698