| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 part of dart.core; | |
| 6 | |
| 7 /** | |
| 8 * A [Future] is used to obtain a value sometime in the future. Receivers of a | |
| 9 * [Future] can obtain the value by passing a callback to [then]. For example: | |
| 10 * | |
| 11 * Future<int> future = getFutureFromSomewhere(); | |
| 12 * future.then((value) { | |
| 13 * print("I received the number $value"); | |
| 14 * }); | |
| 15 * | |
| 16 * A future may complete by *succeeding* (producing a value) or *failing* | |
| 17 * (producing an exception, which may be handled with [handleException]). | |
| 18 * Callbacks passed to [onComplete] will be invoked in either case. | |
| 19 * | |
| 20 * When a future completes, the following actions happen in order: | |
| 21 * | |
| 22 * 1. if the future suceeded, handlers registered with [then] are called. | |
| 23 * 2. if the future failed, handlers registered with [handleException] are | |
| 24 * called in sequence, until one returns true. | |
| 25 * 3. handlers registered with [onComplete] are called | |
| 26 * 4. if the future failed, and at least one handler was registered with | |
| 27 * [then], and no handler registered with [handleException] returned | |
| 28 * [:true:], then the exception is thrown. | |
| 29 * | |
| 30 * Use a [Completer] to create and change the state of a [Future]. | |
| 31 */ | |
| 32 abstract class Future<T> { | |
| 33 /** A future whose value is immediately available. */ | |
| 34 factory Future.immediate(T value) => new _FutureImpl<T>.immediate(value); | |
| 35 | |
| 36 /** The value provided. Throws an exception if [hasValue] is false. */ | |
| 37 T get value; | |
| 38 | |
| 39 /** | |
| 40 * Exception that occurred ([:null:] if no exception occured). This property | |
| 41 * throws a [FutureNotCompleteException] if it is used before this future is | |
| 42 * completes. | |
| 43 */ | |
| 44 Object get exception; | |
| 45 | |
| 46 /** | |
| 47 * The stack trace object associated with the exception that occurred. This | |
| 48 * throws a [FutureNotCompleteException] if it is used before the future | |
| 49 * completes. Returns [:null:] if the future completed successfully or a | |
| 50 * stack trace wasn't provided with the exception when it occurred. | |
| 51 */ | |
| 52 Object get stackTrace; | |
| 53 | |
| 54 /** | |
| 55 * Whether the future is complete (either the value is available or there was | |
| 56 * an exception). | |
| 57 */ | |
| 58 bool get isComplete; | |
| 59 | |
| 60 /** | |
| 61 * Whether the value is available (meaning [isComplete] is true, and there was | |
| 62 * no exception). | |
| 63 */ | |
| 64 bool get hasValue; | |
| 65 | |
| 66 /** | |
| 67 * When this future is complete (either with a value or with an exception), | |
| 68 * then [complete] is called with the future. | |
| 69 * If [complete] throws an exception, it is ignored. | |
| 70 */ | |
| 71 void onComplete(void complete(Future<T> future)); | |
| 72 | |
| 73 /** | |
| 74 * If this future is complete and has a value, then [onSuccess] is called | |
| 75 * with the value. | |
| 76 */ | |
| 77 void then(void onSuccess(T value)); | |
| 78 | |
| 79 /** | |
| 80 * If this future is complete and has an exception, then call [onException]. | |
| 81 * | |
| 82 * If [onException] returns true, then the exception is considered handled. | |
| 83 * | |
| 84 * If [onException] does not return true (or [handleException] was never | |
| 85 * called), then the exception is not considered handled. In that case, if | |
| 86 * there were any calls to [then], then the exception will be thrown when the | |
| 87 * value is set. | |
| 88 * | |
| 89 * In most cases it should not be necessary to call [handleException], | |
| 90 * because the exception associated with this [Future] will propagate | |
| 91 * naturally if the future's value is being consumed. Only call | |
| 92 * [handleException] if you need to do some special local exception handling | |
| 93 * related to this particular Future's value. | |
| 94 */ | |
| 95 void handleException(bool onException(Object exception)); | |
| 96 | |
| 97 /** | |
| 98 * A future representing [transformation] applied to this future's value. | |
| 99 * | |
| 100 * When this future gets a value, [transformation] will be called on the | |
| 101 * value, and the returned future will receive the result. | |
| 102 * | |
| 103 * If an exception occurs (received by this future, or thrown by | |
| 104 * [transformation]) then the returned future will receive the exception. | |
| 105 * | |
| 106 * You must not add exception handlers to [this] future prior to calling | |
| 107 * transform, and any you add afterwards will not be invoked. | |
| 108 */ | |
| 109 Future transform(transformation(T value)); | |
| 110 | |
| 111 /** | |
| 112 * A future representing an asynchronous transformation applied to this | |
| 113 * future's value. [transformation] must return a Future. | |
| 114 * | |
| 115 * When this future gets a value, [transformation] will be called on the | |
| 116 * value. When the resulting future gets a value, the returned future | |
| 117 * will receive it. | |
| 118 * | |
| 119 * If an exception occurs (received by this future, thrown by | |
| 120 * [transformation], or received by the future returned by [transformation]) | |
| 121 * then the returned future will receive the exception. | |
| 122 * | |
| 123 * You must not add exception handlers to [this] future prior to calling | |
| 124 * chain, and any you add afterwards will not be invoked. | |
| 125 */ | |
| 126 Future chain(Future transformation(T value)); | |
| 127 | |
| 128 /** | |
| 129 * A future representing [transformation] applied to this future's exception. | |
| 130 * This can be used to "catch" an exception coming from `this` and translate | |
| 131 * it to a more appropriate result. | |
| 132 * | |
| 133 * If this future gets a value, it simply completes to that same value. If an | |
| 134 * exception occurs, then [transformation] will be called with the exception | |
| 135 * value. If [transformation] itself throws an exception, then the returned | |
| 136 * future completes with that exception. Otherwise, the future will complete | |
| 137 * with the value returned by [transformation]. If the returned value is | |
| 138 * itself a future, then the future returned by [transformException] will | |
| 139 * complete with the value that that future completes to. | |
| 140 */ | |
| 141 Future transformException(transformation(Object exception)); | |
| 142 } | |
| 143 | |
| 144 /** | |
| 145 * A [Completer] is used to produce [Future]s and supply their value when it | |
| 146 * becomes available. | |
| 147 * | |
| 148 * A service that provides values to callers, and wants to return [Future]s can | |
| 149 * use a [Completer] as follows: | |
| 150 * | |
| 151 * Completer completer = new Completer(); | |
| 152 * // send future object back to client... | |
| 153 * return completer.future; | |
| 154 * ... | |
| 155 * | |
| 156 * // later when value is available, call: | |
| 157 * completer.complete(value); | |
| 158 * | |
| 159 * // alternatively, if the service cannot produce the value, it | |
| 160 * // can provide an exception: | |
| 161 * completer.completeException(exception); | |
| 162 * | |
| 163 */ | |
| 164 abstract class Completer<T> { | |
| 165 | |
| 166 factory Completer() => new _CompleterImpl<T>(); | |
| 167 | |
| 168 /** The future that will contain the value produced by this completer. */ | |
| 169 Future get future; | |
| 170 | |
| 171 /** Supply a value for [future]. */ | |
| 172 void complete(T value); | |
| 173 | |
| 174 /** | |
| 175 * Indicate in [future] that an exception occured while trying to produce its | |
| 176 * value. The argument [exception] should not be [:null:]. A [stackTrace] | |
| 177 * object can be provided as well to give the user information about where | |
| 178 * the error occurred. If omitted, it will be [:null:]. | |
| 179 */ | |
| 180 void completeException(Object exception, [Object stackTrace]); | |
| 181 } | |
| 182 | |
| 183 /** Thrown when reading a future's properties before it is complete. */ | |
| 184 class FutureNotCompleteException implements Exception { | |
| 185 FutureNotCompleteException() {} | |
| 186 String toString() => "Exception: future has not been completed"; | |
| 187 } | |
| 188 | |
| 189 /** | |
| 190 * Thrown if a completer tries to set the value on a future that is already | |
| 191 * complete. | |
| 192 */ | |
| 193 class FutureAlreadyCompleteException implements Exception { | |
| 194 FutureAlreadyCompleteException() {} | |
| 195 String toString() => "Exception: future already completed"; | |
| 196 } | |
| 197 | |
| 198 /** | |
| 199 * Wraps unhandled exceptions provided to [Completer.completeException]. It is | |
| 200 * used to show both the error message and the stack trace for unhandled | |
| 201 * exceptions. | |
| 202 */ | |
| 203 class FutureUnhandledException implements Exception { | |
| 204 /** Wrapped exception. */ | |
| 205 var source; | |
| 206 | |
| 207 /** Trace for the wrapped exception. */ | |
| 208 Object stackTrace; | |
| 209 | |
| 210 FutureUnhandledException(this.source, this.stackTrace); | |
| 211 | |
| 212 String toString() { | |
| 213 return 'FutureUnhandledException: exception while executing Future\n ' | |
| 214 '${source.toString().replaceAll("\n", "\n ")}\n' | |
| 215 'original stack trace:\n ' | |
| 216 '${stackTrace.toString().replaceAll("\n","\n ")}'; | |
| 217 } | |
| 218 } | |
| 219 | |
| 220 | |
| 221 /** | |
| 222 * [Futures] holds additional utility functions that operate on [Future]s (for | |
| 223 * example, waiting for a collection of Futures to complete). | |
| 224 */ | |
| 225 class Futures { | |
| 226 /** | |
| 227 * Returns a future which will complete once all the futures in a list are | |
| 228 * complete. If any of the futures in the list completes with an exception, | |
| 229 * the resulting future also completes with an exception. (The value of the | |
| 230 * returned future will be a list of all the values that were produced.) | |
| 231 */ | |
| 232 static Future<List> wait(List<Future> futures) { | |
| 233 if (futures.isEmpty) { | |
| 234 return new Future<List>.immediate(const []); | |
| 235 } | |
| 236 | |
| 237 Completer completer = new Completer<List>(); | |
| 238 Future<List> result = completer.future; | |
| 239 int remaining = futures.length; | |
| 240 List values = new List(futures.length); | |
| 241 | |
| 242 // As each future completes, put its value into the corresponding | |
| 243 // position in the list of values. | |
| 244 for (int i = 0; i < futures.length; i++) { | |
| 245 // TODO(mattsh) - remove this after bug | |
| 246 // http://code.google.com/p/dart/issues/detail?id=333 is fixed. | |
| 247 int pos = i; | |
| 248 Future future = futures[pos]; | |
| 249 future.then((Object value) { | |
| 250 values[pos] = value; | |
| 251 if (--remaining == 0 && !result.isComplete) { | |
| 252 completer.complete(values); | |
| 253 } | |
| 254 }); | |
| 255 future.handleException((exception) { | |
| 256 if (!result.isComplete) { | |
| 257 completer.completeException(exception, future.stackTrace); | |
| 258 } | |
| 259 return true; | |
| 260 }); | |
| 261 } | |
| 262 return result; | |
| 263 } | |
| 264 | |
| 265 /** | |
| 266 * Runs [f] for each element in [input] in order, moving to the next element | |
| 267 * only when the [Future] returned by [f] completes. Returns a [Future] that | |
| 268 * completes when all elements have been processed. | |
| 269 * | |
| 270 * The return values of all [Future]s are discarded. Any errors will cause the | |
| 271 * iteration to stop and will be piped through the returned [Future]. | |
| 272 */ | |
| 273 static Future forEach(Iterable input, Future f(element)) { | |
| 274 var iterator = input.iterator(); | |
| 275 Future nextElement(_) { | |
| 276 if (!iterator.hasNext) return new Future.immediate(null); | |
| 277 return f(iterator.next()).chain(nextElement); | |
| 278 } | |
| 279 return nextElement(null); | |
| 280 } | |
| 281 } | |
| OLD | NEW |