OLD | NEW |
| (Empty) |
1 // Copyright 2013 Google Inc. All Rights Reserved. | |
2 // | |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
4 // you may not use this file except in compliance with the License. | |
5 // You may obtain a copy of the License at | |
6 // | |
7 // http://www.apache.org/licenses/LICENSE-2.0 | |
8 // | |
9 // Unless required by applicable law or agreed to in writing, software | |
10 // distributed under the License is distributed on an "AS IS" BASIS, | |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 // See the License for the specific language governing permissions and | |
13 // limitations under the License. | |
14 | |
15 part of quiver.async; | |
16 | |
17 /** | |
18 * An asynchronous callback that returns a value. | |
19 */ | |
20 typedef Future<T> AsyncAction<T>(e); | |
21 | |
22 /** | |
23 * An asynchronous funcuntion that combines an element [e] with a previous value | |
24 * [previous], for use with [reduceAsync]. | |
25 */ | |
26 typedef Future<T> AsyncCombiner<T>(T previous, e); | |
27 | |
28 /** | |
29 * Calls [action] for each item in [iterable] in turn, waiting for the Future | |
30 * returned by action to complete. | |
31 * | |
32 * If the Future completes to [true], iteration continues. | |
33 * | |
34 * The Future returned completes to [true] if the entire iterable was processed, | |
35 * otherwise [false]. | |
36 */ | |
37 Future doWhileAsync(Iterable iterable, AsyncAction<bool> action) => | |
38 _doWhileAsync(iterable.iterator, action); | |
39 | |
40 Future _doWhileAsync( | |
41 Iterator iterator, AsyncAction<bool> action) => (iterator.moveNext()) | |
42 ? action(iterator.current).then((bool result) => | |
43 (result) ? _doWhileAsync(iterator, action) : new Future.value(false)) | |
44 : new Future.value(true); | |
45 | |
46 /** | |
47 * Reduces a collection to a single value by iteratively combining elements | |
48 * of the collection using the provided [combine] function. Similar to | |
49 * [Iterable.reduce], except that [combine] is an async function that returns a | |
50 * [Future]. | |
51 */ | |
52 Future reduceAsync(Iterable iterable, initialValue, AsyncCombiner combine) => | |
53 _reduceAsync(iterable.iterator, initialValue, combine); | |
54 | |
55 Future _reduceAsync(Iterator iterator, currentValue, AsyncCombiner combine) { | |
56 if (iterator.moveNext()) { | |
57 return combine(currentValue, iterator.current) | |
58 .then((result) => _reduceAsync(iterator, result, combine)); | |
59 } | |
60 return new Future.value(currentValue); | |
61 } | |
62 | |
63 /** | |
64 * Schedules calls to [action] for each element in [iterable]. No more than | |
65 * [maxTasks] calls to [action] will be pending at once. | |
66 */ | |
67 Future forEachAsync(Iterable iterable, AsyncAction action, {int maxTasks: 1}) { | |
68 if (maxTasks == null || maxTasks < 1) { | |
69 throw new ArgumentError("maxTasks must be greater than 0, was: $maxTasks"); | |
70 } | |
71 | |
72 if (iterable == null) { | |
73 throw new ArgumentError("iterable must not be null"); | |
74 } | |
75 | |
76 if (iterable.isEmpty) return new Future.value(); | |
77 | |
78 var completer = new Completer(); | |
79 var iterator = iterable.iterator; | |
80 int pending = 0; | |
81 bool failed = false; | |
82 | |
83 bool scheduleTask() { | |
84 if (pending < maxTasks && iterator.moveNext()) { | |
85 pending++; | |
86 var item = iterator.current; | |
87 scheduleMicrotask(() { | |
88 var task = action(item); | |
89 task.then((_) { | |
90 pending--; | |
91 if (failed) return; | |
92 if (!scheduleTask() && pending == 0) { | |
93 completer.complete(); | |
94 } | |
95 }).catchError((e) { | |
96 if (failed) return; | |
97 failed = true; | |
98 completer.completeError(e); | |
99 }); | |
100 }); | |
101 return true; | |
102 } | |
103 return false; | |
104 } | |
105 while (scheduleTask()) {} | |
106 return completer.future; | |
107 } | |
OLD | NEW |