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