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 |