OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library async.future_group; | |
6 | |
7 import 'dart:async'; | 5 import 'dart:async'; |
8 | 6 |
9 /// A collection of futures waits until all added [Future]s complete. | 7 /// A collection of futures waits until all added [Future]s complete. |
10 /// | 8 /// |
11 /// Futures are added to the group with [add]. Once you're finished adding | 9 /// Futures are added to the group with [add]. Once you're finished adding |
12 /// futures, signal that by calling [close]. Then, once all added futures have | 10 /// futures, signal that by calling [close]. Then, once all added futures have |
13 /// completed, [future] will complete with a list of values from the futures in | 11 /// completed, [future] will complete with a list of values from the futures in |
14 /// the group, in the order they were added. | 12 /// the group, in the order they were added. |
15 /// | 13 /// |
16 /// If any added future completes with an error, [future] will emit that error | 14 /// If any added future completes with an error, [future] will emit that error |
(...skipping 11 matching lines...) Expand all Loading... |
28 var _closed = false; | 26 var _closed = false; |
29 | 27 |
30 /// The future that fires once [close] has been called and all futures in the | 28 /// The future that fires once [close] has been called and all futures in the |
31 /// group have completed. | 29 /// group have completed. |
32 /// | 30 /// |
33 /// This will also complete with an error if any of the futures in the group | 31 /// This will also complete with an error if any of the futures in the group |
34 /// fails, regardless of whether [close] was called. | 32 /// fails, regardless of whether [close] was called. |
35 Future<List<T>> get future => _completer.future; | 33 Future<List<T>> get future => _completer.future; |
36 final _completer = new Completer<List<T>>(); | 34 final _completer = new Completer<List<T>>(); |
37 | 35 |
38 /// Whether this group is waiting on any futures. | 36 /// Whether this group has no pending futures. |
39 bool get isIdle => _pending == 0; | 37 bool get isIdle => _pending == 0; |
40 | 38 |
41 /// A broadcast stream that emits a `null` event whenever the last pending | 39 /// A broadcast stream that emits a `null` event whenever the last pending |
42 /// future in this group completes. | 40 /// future in this group completes. |
43 /// | 41 /// |
44 /// Once this group isn't waiting on any futures *and* [close] has been | 42 /// Once this group isn't waiting on any futures *and* [close] has been |
45 /// called, this stream will close. | 43 /// called, this stream will close. |
46 Stream get onIdle { | 44 Stream get onIdle { |
47 if (_onIdleController == null) { | 45 if (_onIdleController == null) { |
48 _onIdleController = new StreamController.broadcast(sync: true); | 46 _onIdleController = new StreamController.broadcast(sync: true); |
49 } | 47 } |
50 return _onIdleController.stream; | 48 return _onIdleController.stream; |
51 } | 49 } |
| 50 |
52 StreamController _onIdleController; | 51 StreamController _onIdleController; |
53 | 52 |
54 /// The values emitted by the futures that have been added to the group, in | 53 /// The values emitted by the futures that have been added to the group, in |
55 /// the order they were added. | 54 /// the order they were added. |
56 /// | 55 /// |
57 /// The slots for futures that haven't completed yet are `null`. | 56 /// The slots for futures that haven't completed yet are `null`. |
58 final _values = new List<T>(); | 57 final _values = new List<T>(); |
59 | 58 |
60 /// Wait for [task] to complete. | 59 /// Wait for [task] to complete. |
61 void add(Future<T> task) { | 60 void add(Future<T> task) { |
62 if (_closed) throw new StateError("The FutureGroup is closed."); | 61 if (_closed) throw new StateError("The FutureGroup is closed."); |
63 | 62 |
64 // Ensure that future values are put into [values] in the same order they're | 63 // Ensure that future values are put into [values] in the same order they're |
65 // added to the group by pre-allocating a slot for them and recording its | 64 // added to the group by pre-allocating a slot for them and recording its |
66 // index. | 65 // index. |
67 var index = _values.length; | 66 var index = _values.length; |
68 _values.add(null); | 67 _values.add(null); |
69 | 68 |
70 _pending++; | 69 _pending++; |
71 task.then((value) { | 70 task.then((value) { |
72 if (_completer.isCompleted) return; | 71 if (_completer.isCompleted) return null; |
73 | 72 |
74 _pending--; | 73 _pending--; |
75 _values[index] = value; | 74 _values[index] = value; |
76 | 75 |
77 if (_pending != 0) return; | 76 if (_pending != 0) return null; |
78 if (_onIdleController != null) _onIdleController.add(null); | 77 if (_onIdleController != null) _onIdleController.add(null); |
79 | 78 |
80 if (!_closed) return; | 79 if (!_closed) return null; |
81 if (_onIdleController != null) _onIdleController.close(); | 80 if (_onIdleController != null) _onIdleController.close(); |
82 _completer.complete(_values); | 81 _completer.complete(_values); |
83 }).catchError((error, stackTrace) { | 82 }).catchError((error, stackTrace) { |
84 if (_completer.isCompleted) return; | 83 if (_completer.isCompleted) return null; |
85 _completer.completeError(error, stackTrace); | 84 _completer.completeError(error, stackTrace); |
86 }); | 85 }); |
87 } | 86 } |
88 | 87 |
89 /// Signals to the group that the caller is done adding futures, and so | 88 /// Signals to the group that the caller is done adding futures, and so |
90 /// [future] should fire once all added futures have completed. | 89 /// [future] should fire once all added futures have completed. |
91 void close() { | 90 void close() { |
92 _closed = true; | 91 _closed = true; |
93 if (_pending != 0) return; | 92 if (_pending != 0) return; |
94 if (_completer.isCompleted) return; | 93 if (_completer.isCompleted) return; |
95 _completer.complete(_values); | 94 _completer.complete(_values); |
96 } | 95 } |
97 } | 96 } |
98 | |
OLD | NEW |