Flutter的异步操作

173 阅读3分钟

Future

future 是flutter中的异步操作,和js中的promise相似,future也是拥有三种状态,第一是uncompleted 未完成的状态,第二是 已完成并且携带数据的,第三是 已完成携带报错信息的。

future 完成后的回调函数:future的回调函数和peomise一样,又会返回一个future函数,所以也可以进行链式回调。

  1. then 当函数返回结果时回调then函数.
  2. catchError 当函数抛出错误时回调catchError.
  3. whenComplete 当函数执行完成时执行回调
void main() {
  var future = getname();
  future.then((value){ // 当函数返回结果时回调then函数
     print(value); 
  }).catchError((err){ // 当函数抛出错误时回调catchError
     print('error message: $err'); 
  }).whenComplete(() => print('complete')); // 当函数执行完成时执行回调
}

Future getname(){
  return Future((){
    // throw '123456'; // 抛出错误
    return 'hello world'; // 返回结果
  });
} 

future 的一些构造函数,

  1. Future.value(value)会直接返回value值。
  2. Future.error(error)会直接发那会错误。
  3. Future.delayed(time,function),延时一段time,然后执行function函数
  Future.value('hahah').then((value) => print(value));
  Future.error('errrrr').catchError((error)=>print(error));
  Future.delayed(Duration(seconds: 2),(){
    return 'hello world';
  }).then((value) => print(value));

awite async

awite 必须在async函数中使用。 async 必须返回一个Future。

Future gettime() async{
  var res =  await (){
    sleep(Duration(seconds: 5));
    return 'hello world';
  };
  print(res);
}

streams

Future 表示一个不会立即完成的计算过程。与普通函数直接返回结果不同的是异步函数返回一个将会包含结果的 Future。该 Future 会在结果准备好时通知调用者。

Stream 是一系列异步事件的序列。其类似于一个异步的 Iterable,不同的是当你向 Iterable 获取下一个事件时它会立即给你,但是 Stream 则不会立即给你而是在它准备好时告诉你。

创建streams

  1. 转换现有的 Stream。使用 Stream 类提供的转换类方法,比如 map():便利整个Stream、where():查找符合要求的事件、expand(): 重复每个事件。, 和 take(int count): 截取前多少次事件, 来应对大多数常见的转换需求。
void main() async{
  var counterStream =
    Stream<int>.periodic(const Duration(seconds: 1), (x) => x).take(15);
  counterStream.forEach(print);
}

// 其他的用法
var doubleCounterStream = counterStream.map((int x) => x * 2);
counterStream.where((int x) => x.isEven) // Retain only even integer events.// 是偶数的事件
counterStream.expand((var x) => [x, x]) // Duplicate each event. 重复两次
counterStream.take(5) // Stop after the first five events.前5个事件

如果你需要对转换进行更多的控制,你可以使用 Stream 类的 transform() 方法指定一个 StreamTransformer, dart:convert 库提供的 utf8.decoder 和 LineSplitter 转换器。

  1. 使用 async* 函数创建 Stream。

和 async相似,加在函数前面,函数的返回值是stream,函数体中可以使用 awite for 字段来处理stream的事件流。

当异步生成器函数被调用时会创建一个 Stream,而函数体则会在该 Stream 被监听时开始运行。当函数返回时,Stream 关闭。在函数返回前,你可以使用 yield 或 yield* 语句向该 Stream 提交事件。

void main() async{
  timedCounter(Duration(seconds: 5),10).listen(print);
}
Stream<int> timedCounter(Duration interval, [int? maxCount]) async* {
  int i = 0;
  while (true) {
    await Future.delayed(interval);
    yield i++;
    if (i == maxCount) break;
  }
}

上面的代码从头创建一个stream 还是很少用到的,相比之下第三种方法则会更加实用。

  1. 使用 StreamController 生成 Stream。 通过控制器的方式进行创建,StreamController 可以为你生成一个 Stream,并提供在任何时候、任何地方将事件添加到该 Stream 的方法。该 Stream 具有处理监听器和暂停所需的所有逻辑。控制器对象你可以自行处理而只需返回调用者所需的 Stream 即可。

StreamController 中的 onListenonPauseonResume 和 onCancel 回调,分别对应stream的四个方法。 listen: 监听、pause:暂停、resume:重新开始 和 cancel:取消。

StreamController 的add()方法是向stream中添加事件。close()关闭stream


var counterStream = timedCounter(const Duration(seconds: 1), 15); // 调用方法创建stream 
counterStream.listen(print); // 打印15次


Stream<int> timedCounter(Duration interval, [int? maxCount]) {
 late StreamController<int> controller;
 Timer? timer;
 int counter = 0;

 void tick(_) {
   counter++;
   controller.add(counter); // 向stream 中添加事件
   if (counter == maxCount) {
     timer?.cancel();
     controller.close(); // 关闭stream
   }
 }

 void startTimer() {
   timer = Timer.periodic(interval, tick);
 }

 void stopTimer() {
   timer?.cancel();
   timer = null;
 }

 controller = StreamController<int>(
     onListen: startTimer, // 监听时触发回调函数,开始进行添加事件
     onPause: stopTimer, // 
     onResume: startTimer, //
     onCancel: stopTimer); // 

 return controller.stream;
}