我今天用一些生产代码遇到了这个并且能够用一个简单的.toList()
修复它以在等待之前解析lazyList,但我不明白为什么它以这种方式工作而仅< / em>使用Future.wait()
时这里发生了什么?为什么lazyList被解析两次?
Play with it on DartPad(更改第3行doWait
的值并查看不同的结果)
import 'dart:async';
void main() {
var executedTracker = [];
var source = ["a", "b", "c"];
List promises = source.map((item) async {
print('executing item $item${(executedTracker.contains(item) ? ' (again!? o_O)' : '')}'); executedTracker.add(item);
return (item*2);
});
Future.wait(promises).whenComplete(() {
print('--------\nAll promises complete.');
print('Processing ${promises.length} results...\n');
promises.forEach((promise) => null /* do a thing with the result*/);
});
}
executing item a
executing item b
executing item c
All promises complete.
Processing 3 results...
executing item a (again!? o_O)
executing item b (again!? o_O)
executing item c (again!? o_O)
答案 0 :(得分:4)
因为您在promises
中进行了两次Future.wait(promises)
次迭代,在promises.forEach(...)
中进行了一次。
(幸运的是promises.length
- 因为映射的iterable知道它基于列表,所以它不会再次迭代以找到长度。)
映射的iterable的每次迭代都将重新迭代原始的iterable并再次执行map操作,这意味着它是一个惰性转换。对于像hugelyGiganticIterable.map(something).take(10).toList()
这样的案件来说,懒惰是必要的。如果它不是懒惰的话,它会对巨大巨大的迭代中的所有元素执行映射(它甚至可以是无限的,迭代可以是无限的,与列表不同)。
在一个真实示例中,您可能想要做的是使用Future.wait(promises)
操作的结果:
Future.wait(promises).then((items) {
print('--------\nAll promises complete.');
print('Processing ${items.length} results...\n');
items.forEach((item) => null /* do a thing with the *result* */);
});
如果您实际上想要懒惰的行为,那么您应该急切地收集这些值。你可以这样做,例如写下:
List promises = source.map((item) async {
...
}).toList(); // <-- notice the ".toList()"!
使用toList
强制评估iterable的每个映射元素,从而消除惰性。