Chromium Code Reviews| Index: sdk/lib/async/future.dart |
| diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart |
| index 595489e890f4adb45498f6a66b00b9551ea629ae..74c0d91a5646fa424d5ac579bf9e074a314061b9 100644 |
| --- a/sdk/lib/async/future.dart |
| +++ b/sdk/lib/async/future.dart |
| @@ -57,28 +57,33 @@ abstract class FutureOr<T> { |
| * future.then((value) => handleValue(value)) |
| * .catchError((error) => handleError(error)); |
| * |
| - * A [Future] can complete in two ways: |
| + * 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. |
| + * In some cases we say that a future is completed with another future. |
|
floitsch
2017/05/31 15:28:27
Put a line before here. (I think this should be a
Lasse Reichstein Nielsen
2017/06/02 05:53:39
Done.
|
| + * In that case, the other future is waited for, and when it completes, |
|
floitsch
2017/05/31 15:28:27
... with another future. This is a short way of st
Lasse Reichstein Nielsen
2017/06/02 05:53:39
Used with slight rewording.
|
| + * the first future is completed in the same way, with the same value or error. |
| + * |
| * 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: (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. |
| - * } |
| - * }); |
| + * ``` |
| + * 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: (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 when it completes with an error, |
| * it forwards the error message to the global error-handler. |
| @@ -86,16 +91,17 @@ abstract class FutureOr<T> { |
| * 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(new Duration(milliseconds: 5), () { |
| - * // The error-handler is not attached until 5 ms after the future has |
| - * // been received. If the future fails before that, the error is |
| - * // forwarded to the global error-handler, even though there is code |
| - * // (just below) to eventually handle the error. |
| - * future.then((value) { useValue(value); }, |
| - * onError: (e) { handleError(e); }); |
| - * }); |
| + * ``` |
| + * var future = getFuture(); |
| + * new Timer(new Duration(milliseconds: 5), () { |
| + * // The error-handler is not attached until 5 ms after the future has |
| + * // been received. If the future fails before that, the error is |
| + * // forwarded to the global error-handler, even though there is code |
| + * // (just below) to eventually handle the error. |
| + * future.then((value) { useValue(value); }, |
| + * onError: (e) { handleError(e); }); |
| + * }); |
| + * ``` |
| * |
| * When registering callbacks, it's often more readable to register the two |
| * callbacks separately, by first using [then] with one argument |
| @@ -107,20 +113,22 @@ abstract class FutureOr<T> { |
| * Using sequential handlers instead of parallel ones often leads to code that |
| * is easier to reason about. |
| * It also makes asynchronous code very similar to synchronous code: |
| - * |
| - * // Synchronous code. |
| - * try { |
| - * int value = foo(); |
| - * return bar(value); |
| - * } catch (e) { |
| - * return 499; |
| - * } |
| + * ``` |
| + * // Synchronous code. |
| + * try { |
| + * int value = foo(); |
| + * return bar(value); |
| + * } catch (e) { |
| + * return 499; |
| + * } |
| + * ``` |
| * |
| * Equivalent asynchronous code, based on futures: |
| - * |
| - * Future<int> future = new Future(foo); // Result of foo() as a future. |
| - * future.then((int value) => bar(value)) |
| - * .catchError((e) => 499); |
| + * ``` |
| + * Future<int> future = new Future(foo); // Result of foo() as a future. |
| + * future.then((int value) => bar(value)) |
| + * .catchError((e) => 499); |
| + * ``` |
| * |
| * Similar to the synchronous code, the error handler (registered with |
| * [catchError]) is handling any errors thrown by either `foo` or `bar`. |
| @@ -134,9 +142,12 @@ abstract class FutureOr<T> { |
| * called. |
| */ |
| abstract class Future<T> { |
| - // The `_nullFuture` is a completed Future with the value `null`. |
| + /// A `Future<Null>` completed with `null`. |
|
floitsch
2017/05/31 15:28:27
Should we make this one public? It's quite common.
Lasse Reichstein Nielsen
2017/06/02 05:53:39
I'd want to iterate a little on the name if we mak
|
| static final _Future<Null> _nullFuture = new _Future<Null>.value(null); |
| + /// A `Future<bool>` completed with `false`. |
| + static final _Future<bool> _falseFuture = new _Future<bool>.value(false); |
| + |
| /** |
| * Creates a future containing the result of calling [computation] |
| * asynchronously with [Timer.run]. |
| @@ -226,10 +237,14 @@ abstract class Future<T> { |
| } |
| /** |
| - * A future whose value is available in the next event-loop iteration. |
| + * Creates a future completed with [result]. |
|
floitsch
2017/05/31 15:28:27
a future, completed with...
Lasse Reichstein Nielsen
2017/06/02 05:53:39
Don't think that would work, there'd be no subject
|
| * |
| - * If [result] is not a [Future], using this constructor is equivalent |
| - * to `new Future<T>.sync(() => result)`. |
| + * If [result] is a future, this creates a new future that waits for the |
|
floitsch
2017/05/31 15:28:28
"this creates" sounds bad.
The created future wai
Lasse Reichstein Nielsen
2017/06/02 05:53:39
Done.
|
| + * [result] future to complete, and then completes with the same result. |
|
floitsch
2017/05/31 15:28:27
Maybe mention that this means that a Future.value
|
| + * |
| + * If [result] is not a [Future], this creates a future that is already |
|
floitsch
2017/05/31 15:28:27
not a [Future], the returned future
Lasse Reichstein Nielsen
2017/06/02 05:53:39
Done + reworded.
|
| + * completed with th [result] value |
|
floitsch
2017/05/31 15:28:28
the
Lasse Reichstein Nielsen
2017/06/02 05:53:38
Done.
|
| + * equivalent to `new Future<T>.sync(() => result)`. |
| * |
| * Use [Completer] to create a future and complete it later. |
| */ |
| @@ -238,7 +253,12 @@ abstract class Future<T> { |
| } |
| /** |
| - * A future that completes with an error in the next event-loop iteration. |
| + * Creates a future that completes with an error. |
| + * |
| + * The created future will be completed with an error in a future microtask. |
| + * This allows enough time for someone to add an error handler on the future. |
| + * If an error handler isn't added before the future completes, the error |
| + * will be considered unhandled. |
| * |
| * If [error] is `null`, it is replaced by a [NullThrownError]. |
| * |
| @@ -260,12 +280,14 @@ abstract class Future<T> { |
| * Creates a future that runs its computation after a delay. |
| * |
| * The [computation] will be executed after the given [duration] has passed, |
| - * and the future is completed with the result. |
| + * and the future is completed with the result of the computation, |
| + * |
| * If the duration is 0 or less, |
| - * it completes no sooner than in the next event-loop iteration. |
| + * it completes no sooner than in the next event-loop iteration, |
| + * after microtasks have run. |
|
floitsch
2017/05/31 15:28:27
after all microtasks
Lasse Reichstein Nielsen
2017/06/02 05:53:39
OK, but technically not correct - there might be m
|
| * |
| * If [computation] is omitted, |
| - * it will be treated as if [computation] was set to `() => null`, |
| + * it will be treated as if [computation] was `() => null`, |
| * and the future will eventually complete with the `null` value. |
| * |
| * If calling [computation] throws, the created future will complete with the |
| @@ -287,17 +309,18 @@ abstract class Future<T> { |
| } |
| /** |
| - * Wait for all the given futures to complete and collect their values. |
| + * Waits for multiple futures to complete and collects their results. |
| * |
| - * Returns a future which will complete once all the futures in a list |
| - * have completed. |
| + * Returns a future which will complete once all the provided futures |
| + * have completed, either with their results, or with an error if either |
| + * of the provided futures fail. |
| * |
| * The value of the returned future will be a list of all the values that |
| * were produced. |
| * |
| - * If any of the given futures completes with an error, then the returned |
| - * future completes with that error. If other futures complete with errors, |
| - * those errors are discarded. |
| + * If any future completes with an error, |
| + * then the returned future completes with that error. |
| + * If further futures also complete with errors, those errors are discarded. |
| * |
| * If `eagerError` is true, the returned future completes with an error |
| * immediately on the first error from one of the futures. Otherwise all |
| @@ -306,11 +329,11 @@ abstract class Future<T> { |
| * |
| * In the case of an error, [cleanUp] (if provided), is invoked on any |
| * non-null result of successful futures. |
| - * This makes it posible to `cleanUp` resources that would otherwise be |
| - * lost (since the returned future does not provide access to these values). |
| - * The [cleanup] function is unused if there is no error. |
| + * This makes it posible to "clean up" resources that would otherwise be |
| + * lost since the returned future does not provide access to these values. |
| + * The [cleanUp] function is unused if there is no error. |
| * |
| - * The call to `cleanUp` should not throw. If it does, the error will be an |
| + * The call to [cleanUp] should not throw. If it does, the error will be an |
| * uncaught asynchronous error. |
| */ |
| static Future<List<T>> wait<T>(Iterable<Future<T>> futures, |
| @@ -408,7 +431,8 @@ abstract class Future<T> { |
| * Returns the result of the first future in [futures] to complete. |
| * |
| * The returned future is completed with the result of the first |
| - * future in [futures] to report that it is complete. |
| + * future in [futures] to report that it is complete, |
| + * whether it's with a value or an error. |
| * The results of all the other futures are discarded. |
| * |
| * If [futures] is empty, or if none of its futures complete, |
| @@ -429,13 +453,13 @@ abstract class Future<T> { |
| } |
| /** |
| - * Perform an operation for each element of the iterable, in turn. |
| + * Performs an action for each element of the iterable, in turn. |
| * |
| - * The operation, [f], may be either synchronous or asynchronous. |
| + * The [action] may be either synchronous or asynchronous. |
| * |
| - * Calls [f] with each element in [input] in order. |
| - * If the call to [f] returns a `Future<T>`, the iteration waits |
| - * until the future is completed before moving to the next element. |
| + * Calls [action] with each element in [elements] in order. |
| + * If the call to [action] returns a `Future<T>`, the iteration waits |
| + * until the future is completed before continuing with the next element. |
| * |
| * Returns a [Future] that completes with `null` when all elements have been |
| * processed. |
| @@ -443,14 +467,14 @@ abstract class Future<T> { |
| * Non-[Future] return values, and completion-values of returned [Future]s, |
| * are discarded. |
| * |
| - * Any error from [f], synchronous or asynchronous, will stop the iteration |
| - * and will be reported in the returned [Future]. |
| + * Any error from [action], synchronous or asynchronous, |
| + * will stop the iteration and be reported in the returned [Future]. |
| */ |
| - static Future forEach<T>(Iterable<T> input, FutureOr f(T element)) { |
| - var iterator = input.iterator; |
| + static Future forEach<T>(Iterable<T> elements, FutureOr action(T element)) { |
| + var iterator = elements.iterator; |
| return doWhile(() { |
| if (!iterator.moveNext()) return false; |
| - var result = f(iterator.current); |
| + var result = action(iterator.current); |
| if (result is Future) return result.then(_kTrue); |
| return true; |
| }); |
| @@ -475,12 +499,13 @@ abstract class Future<T> { |
| * an error, iteration ends and the future returned by [doWhile] |
| * completes with the same error. |
| * |
| - * Calls to [f] may happen at any time, including immediately after calling |
| - * `doWhile`. The only restriction is a new call to [f] won't happen before |
| + * Calls to [action] may happen at any time, |
| + * including immediately after calling `doWhile`. |
| + * The only restriction is a new call to [action] won't happen before |
| * the previous call has returned, and if it returned a `Future<bool>`, not |
| * until that future has completed. |
| */ |
| - static Future doWhile(FutureOr<bool> f()) { |
| + static Future doWhile(FutureOr<bool> action()) { |
| _Future doneSignal = new _Future(); |
| var nextIteration; |
| // Bind this callback explicitly so that each iteration isn't bound in the |
| @@ -491,7 +516,7 @@ abstract class Future<T> { |
| while (keepGoing) { |
| FutureOr<bool> result; |
| try { |
| - result = f(); |
| + result = action(); |
| } catch (error, stackTrace) { |
| // Cannot use _completeWithErrorCallback because it completes |
| // the future synchronously. |
| @@ -589,29 +614,30 @@ abstract class Future<T> { |
| * See the description on [Future]. |
| * |
| * Example: |
| - * |
| - * foo |
| - * .catchError(..., test: (e) => e is ArgumentError) |
| - * .catchError(..., test: (e) => e is NoSuchMethodError) |
| - * .then((v) { ... }); |
| + * ``` |
|
floitsch
2017/05/31 15:28:28
I would just remove this example. Way too complica
Lasse Reichstein Nielsen
2017/06/02 05:53:38
Removed.
|
| + * foo |
| + * .catchError(..., test: (e) => e is ArgumentError) |
| + * .catchError(..., test: (e) => e is NoSuchMethodError) |
| + * .then((v) { ... }); |
| + * ``` |
| * |
| * This method is equivalent to: |
| - * |
| - * Future catchError(onError(error), |
| - * {bool test(error)}) { |
| - * this.then((v) => v, // Forward the value. |
| - * // But handle errors, if the [test] succeeds. |
| - * onError: (e, stackTrace) { |
| - * if (test == null || test(e)) { |
| - * if (onError is ZoneBinaryCallback) { |
| - * return onError(e, stackTrace); |
| - * } |
| - * return onError(e); |
| - * } |
| - * throw e; |
| - * }); |
| - * } |
| - * |
| + * ``` |
| + * Future catchError(onError(error), |
| + * {bool test(error)}) { |
| + * this.then((v) => v, // Forward the value. |
| + * // But handle errors, if the [test] succeeds. |
| + * onError: (e, stackTrace) { |
| + * if (test == null || test(e)) { |
| + * if (onError is ZoneBinaryCallback) { |
| + * return onError(e, stackTrace); |
| + * } |
| + * return onError(e); |
| + * } |
| + * throw e; |
| + * }); |
| + * } |
| + * ``` |
| */ |
| // The `Function` below stands for one of two types: |
| // - (dynamic) -> FutureOr<T> |
| @@ -623,7 +649,7 @@ abstract class Future<T> { |
| Future<T> catchError(Function onError, {bool test(Object error)}); |
| /** |
| - * Register a function to be called when this future completes. |
| + * Registers a function to be called when this future completes. |
| * |
| * The [action] function is called when this future completes, whether it |
| * does so with a value or with an error. |
| @@ -713,41 +739,42 @@ class TimeoutException implements Exception { |
| * Most of the time, the simplest way to create a future is to just use |
| * one of the [Future] constructors to capture the result of a single |
| * asynchronous computation: |
| - * |
| - * new Future(() { doSomething(); return result; }); |
| - * |
| + * ``` |
| + * new Future(() { doSomething(); return result; }); |
| + * ``` |
| * or, if the future represents the result of a sequence of asynchronous |
| * computations, they can be chained using [Future.then] or similar functions |
| * on [Future]: |
| - * |
| - * Future doStuff(){ |
| - * return someAsyncOperation().then((result) { |
| - * return someOtherAsyncOperation(result); |
| - * }); |
| - * } |
| - * |
| + * ``` |
| + * Future doStuff(){ |
| + * return someAsyncOperation().then((result) { |
| + * return someOtherAsyncOperation(result); |
| + * }); |
| + * } |
| + * ``` |
| * If you do need to create a Future from scratch — for example, |
| * when you're converting a callback-based API into a Future-based |
| * one — you can use a Completer as follows: |
| + * ``` |
| + * class AsyncOperation { |
| + * Completer _completer = new Completer(); |
| * |
| - * class AsyncOperation { |
| - * Completer _completer = new Completer(); |
| - * |
| - * Future<T> doOperation() { |
| - * _startOperation(); |
| - * return _completer.future; // Send future object back to client. |
| - * } |
| + * Future<T> doOperation() { |
| + * _startOperation(); |
| + * return _completer.future; // Send future object back to client. |
| + * } |
| * |
| - * // Something calls this when the value is ready. |
| - * void _finishOperation(T result) { |
| - * _completer.complete(result); |
| - * } |
| + * // Something calls this when the value is ready. |
| + * void _finishOperation(T result) { |
| + * _completer.complete(result); |
| + * } |
| * |
| - * // If something goes wrong, call this. |
| - * void _errorHappened(error) { |
| - * _completer.completeError(error); |
| - * } |
| - * } |
| + * // If something goes wrong, call this. |
| + * void _errorHappened(error) { |
| + * _completer.completeError(error); |
| + * } |
| + * } |
| + * ``` |
| */ |
| abstract class Completer<T> { |
| /** |
| @@ -758,17 +785,18 @@ abstract class Completer<T> { |
| * either [complete] or [completeError]. |
| * |
| * The completer completes the future asynchronously. That means that |
| - * callbacks registered on the future, are not called immediately when |
| + * callbacks registered on the future are not called immediately when |
| * [complete] or [completeError] is called. Instead the callbacks are |
| * delayed until a later microtask. |
| * |
| * Example: |
| - * |
| - * var completer = new Completer(); |
| - * handOut(completer.future); |
| - * later: { |
| - * completer.complete('completion value'); |
| - * } |
| + * ``` |
| + * var completer = new Completer(); |
| + * handOut(completer.future); |
| + * later: { |
| + * completer.complete('completion value'); |
| + * } |
| + * ``` |
| */ |
| factory Completer() => new _AsyncCompleter<T>(); |
| @@ -824,7 +852,7 @@ abstract class Completer<T> { |
| */ |
| factory Completer.sync() => new _SyncCompleter<T>(); |
| - /** The future that will contain the result provided to this completer. */ |
| + /** The future completed by this completer. */ |
|
floitsch
2017/05/31 15:28:27
It's not always completed yet.
maybe?
The future
Lasse Reichstein Nielsen
2017/06/02 05:53:38
I think it can work as written. "Completed by" can
|
| Future<T> get future; |
| /** |
| @@ -837,7 +865,7 @@ abstract class Completer<T> { |
| * to complete, and complete with the same result, whether it is a success |
| * or an error. |
| * |
| - * Calling `complete` or [completeError] must not be done more than once. |
| + * Calling [complete] or [completeError] must be done at most once. |
| * |
| * All listeners on the future are informed about the value. |
| */ |
| @@ -846,7 +874,7 @@ abstract class Completer<T> { |
| /** |
| * Complete [future] with an error. |
| * |
| - * Calling [complete] or `completeError` must not be done more than once. |
| + * Calling [complete] or [completeError] must be done at most once. |
| * |
| * Completing a future with an error indicates that an exception was thrown |
| * while trying to produce a value. |
| @@ -855,18 +883,25 @@ abstract class Completer<T> { |
| * |
| * If `error` is a `Future`, the future itself is used as the error value. |
| * If you want to complete with the result of the future, you can use: |
| - * |
| - * thisCompleter.complete(theFuture) |
| - * |
| + * ``` |
| + * thisCompleter.complete(theFuture) |
| + * ``` |
| * or if you only want to handle an error from the future: |
| - * |
| - * theFuture.catchError(thisCompleter.completeError); |
| - * |
| + * ``` |
| + * theFuture.catchError(thisCompleter.completeError); |
| + * ``` |
| */ |
| void completeError(Object error, [StackTrace stackTrace]); |
| /** |
| - * Whether the future has been completed. |
| + * Whether the [future] has been completed. |
| + * |
| + * Actually reflects whether [complete] or [completeError] has been called. |
|
floitsch
2017/05/31 15:28:27
Remove "Actually".
|
| + * If [complete] is called with a future, the actual completion my happen |
|
floitsch
2017/05/31 15:28:27
That sounds wrong (and I interpreted it the wrong
Lasse Reichstein Nielsen
2017/06/02 05:53:39
Reworded to something like that.
(It doesn't wait
|
| + * later. |
| + * |
| + * When this value is `true`, [complete] and [completeError] must not be |
| + * called again. |
| */ |
| bool get isCompleted; |
| } |
| @@ -882,7 +917,7 @@ void _completeWithErrorCallback(_Future result, error, stackTrace) { |
| result._completeError(error, stackTrace); |
| } |
| -// Like [_completeWIthErrorCallback] but completes asynchronously. |
| +// Like [_completeWithErrorCallback] but completes asynchronously. |
| void _asyncCompleteWithErrorCallback(_Future result, error, stackTrace) { |
| AsyncError replacement = Zone.current.errorCallback(error, stackTrace); |
| if (replacement != null) { |