平时咱们在写业务逻辑的时候,确定都会与网络打交道,那确定也就避免不了异步请求,代码相似以下:微信
int getData() async {
Response r = await Dio().get('https://www.baidu.com');
return r.data;
}
复制代码
这段代码相信不少人都很是很是熟悉了,咱们也都知道 async 是什么意思,那加上一个星号,你还知道吗?网络
加上星号其实就是「函数生成器」的意思。异步
那咱们先从「sync/sync*」提及。async
「sync」咱们都知道是默认程序运行的状态,举个例子:函数
foo1 (){
print('foo1 start');
for(int i = 0; i < 3; i++){
print(i);
}
print('foo1 stop');
}
复制代码
当咱们在 main
函数里运行,结果你们应该都很清楚:ui
foo1 startspa
0 1 2code
foo1 stopcdn
那所谓的函数生成器呢?接口
被「sync*」标记的函数,必定要返回一个 「Iterable」,这样的函数生成器叫作同步生成器:
Iterable<int> foo2() sync*{
print('foo2 start');
for(int i = 0; i < 3; i++){
print('运行了foo2,当前index:${i}');
yield i;
}
print('foo2 stop');
}
复制代码
这回咱们在 main
函数里运行 foo2()
,会出现什么效果?
答案是什么也不会发生,print也没有打印。
这是为何?
当咱们调用 foo2()
的时候,这里会立刻返回一个 Iterable
,就像网络请求会立刻返回一个 Feature
同样。
可是在咱们没有调用 Iterable
的 moveNext
的时候,当前函数体是不会执行的。
而当咱们调用了 moveNext
方法后,代码会执行到 yield
关键字的位置,而且在这里停住。
当咱们再一次调用 moveNext
后,会再恢复执行,而后再次停到 yield
关键字的位置,依次循环,当没有下一个值得时候,函数会隐式的调用 return方法来终止函数。
来看一下调用方式和结果:
var b = foo2().iterator;
print('还没开始调用 moveNext');
b.moveNext();
print('第${b.current}次moveNext');
b.moveNext();
print('第${b.current}次moveNext');
b.moveNext();
print('第${b.current}次moveNext');
复制代码
结果为:
还没开始调用 moveNext
foo2 start
运行了foo2,当前index:0
第0次moveNext
运行了foo2,当前index:1
第1次moveNext
运行了foo2,当前index:2
第2次moveNext
复制代码
从运行结果上来看,咱们的说法是正确的,下面就来讲一下异步生成器。
说异步生成器以前,先来讲一下普通的异步调用。
如今有一个这样的需求,我想每隔一秒钟请求一下数据,一共请求10次,看看有没有人关注我等等,
若是使用原始的 async,该怎么作?
getData() async {
for (int i = 0; i < 10; i++){
await Future.delayed(Duration(seconds: 1), ()async {
Data data = await getXXX();
setState(){
//业务逻辑
};
});
}
}
复制代码
这里使用循环,而后每一秒钟请求依次接口,返回数据后 setState();
这样确定不行,由于你不可能一两秒钟就 setState()一次,
这个时候 async* 就派上用场了:
Stream<Data> getData() async* {
for (int i = 0; i < 10; i++){
await Future.delayed(Duration(seconds: 1));
yield await getXXX();
}
}
复制代码
在页面上,咱们能够用 StreamBuilder
来包住,这样每次返回数据就不用 setState() 了。
其实函数生成器可能一年都用不上一两次,可是当你用到以后,就会以为真的很舒服。
其实我我的认为这种函数生成器还有一种做用就是能够让一个函数返回多个值。
另我我的建立了一个「Flutter 交流群」,能够添加我我的微信 「17610912320」来入群。
推荐阅读:
Flutter | 思路解析 WPopupMenu 仿微信聊天长按弹出菜单