06 Dart异步和同步关键字应用
1 sync*
和yield
多元素同步迭代使用
1.1 sync*
和 yield
的元素组同步迭代
在dart
中的yield
应用于方法或函数中,起到暂停的作用,加上关键字sync*
后,则返回一个Iterior
类型。而Iterior
的
成员取决于方法内有多少个yield
暂停.
group('keyword yield and sync* Test ', () {
test('Length test', () {
Iterable<String> getItems() sync* {
yield 'hello';
yield 'world';
}
print(getItems().length); // 2
});
});
1.2 代码迭代和for
遍历的区别
所以有当多个元素中进行同步迭代时,能执行到多少个yield
则算多少个元素。
那么这样的来写代码有什么用?能解决什么样场景的问题?假设一个有限集合,而我们要找的其中的一个元素就在其中,而每读取一个元素,意味着,
计算机运行到下一个yield
并返回当前yield
的结果。我们可以通过这一结果再决定要不要接送执行下去。 其运行的结果同for
遍历一样。如,
test('Foreach Iterable', () {
Iterable<String> getItems() sync* {
yield 'hello';
yield 'world';
}
getItems().forEach(print);
// hello
// world
});
结果很明显,这种遍历for
也是可以实现同样的效果,那为什么要用迭代器呢?使用迭代器相对于for
遍历,可以有效去控制内存。如for
遍历列表时,需要
把数据都加载到内存中,然后进行遍历,假设一个列表,里面有n
个元素,那么,使用for
来遍历的话,只能把数据都加载进来,再进行遍历,而使用yield
来
处理的话,就可以每要把执行下一个yield
则,这里的处理逻辑则可以写成以游标的方式去读取该条数据,然后返回结果并暂停。相对来说,占用内存可以更少。如:
test('Foreach Iterable', () {
// 假设这是从文件中读取一个单词出来
String readFromFile(int index) => ['hello', 'wolrd'][index];
Iterable<String> getItems() sync* {
for (var index = 0; index < 2; index++) {
yield readFromFile(index);
}
}
getItems().map(prints);
// hello
// world
});
所以相交于for
的一次性遍历需要加载全部的数据,Iterable
可以通过一个游标的方式一个一个去读取数据,从而不会一开始就占用过多的内存。
2 sync*
和yield*
多元素同步迭代使用
yield*
关键字后接Iterable
,可以理解成,yield*
后面对接的就是另一个迭代集,如果把函数中的yield
比作是一个元素的话,那么yield*
就是把一个整个
元素集拿过来到这个函数中进行一个一个迭代。
test('Test for sync* yield*', () {
Iterable<String> getEmojiWithTime(int count) sync* {
Iterable<String> getItems() sync* {
yield 'hello';
yield 'world';
}
yield* getItems();
yield '!';
}
print(getEmojiWithTime(10).join(' ')); // hello world !
});
3 单元素异步处理async
和await
async
和await
本质上是对一个回调嵌套的函数进行同步写法,从而避免了回调地狱的情况。如:
test( 'async await test', () async {
Future.delayed(const Duration(seconds: 1)).then((value) {
print('OK');
});
await Future.delayed(Duration(seconds: 3));
},
);
这2种写法的作用是一样的,不过,用await
的语法糖方式避免了嵌套的写法,给人一种串行的代码形式,其实本质还是以回调的方式实现异步的,只是通过await
语法糖形式简化了写法,避免开发者不必要的心理负担。
4 多元素异步处理: async*
, yield
和await
在一个函数内使用async*
, yield
和await
,那么这个函数必然返回一个Stream<T>
对象.其结果同多元素同步处理的一样,只不过返回的是Stream<T>
对象。
test('Multiple async test', () async {
Future<String> getWord() async => 'Hello world!';
Stream<String> getStream() async* {
yield await getWord();
}
getStream().listen(print);
await Future.delayed(const Duration(seconds: 3));
});
5 多元素异步嵌套处理: async*
, yield*
和await
其实这个跟上面的async*
, yield
和await
,唯一的区别可以看成是在yield*
并入了一个流.然后先处理完这个流,再执行一个yield
或yield*
test('Multiple async* test', () async {
Stream<String> getWord() async* {
yield await Future(() => 'Hello world!');
yield await Future(() => 'Hello world!');
}
Stream<String> getStream() async* {
yield* getWord();
}
getStream().listen(print);
await Future.delayed(const Duration(seconds: 3));
});