当前位置: 代码迷 >> 综合 >> Dart Future模型 async 和 await
  详细解决方案

Dart Future模型 async 和 await

热度:6   发布时间:2023-12-10 22:02:33.0

Dart汇总请点击这里

本文已重新梳理归纳为异步三部曲 请观众老爷移步观看

  • Dart 异步模型
  • Dart 事件循环
  • Dart 任务调度

Future

Future模型是将异步请求和代理模式结合的产物。
Future类是对未来结果的一个代理,它返回的并不是被调用的任务的返回值。

//我的任务
void  myTask(){
    print("this is my task");
}void  main() {
    Future fut = new  Future(myTask);//根据我的任务创建Future对象
}

如上代码,Future类实例fut并不是函数myTask的返回值,它只是代理了myTask函数,封装了该任务的执行状态。换种理解方式就是,Future就是一个受你委托的委托人,你将未来要执行的任务交给他,你告知他任务类型是耗时任务,还是非耗时任务,然后分类放到事件循环中去,当任务完成后,它会第一时间执行回调方法告知你任务完成,或者会等到你委托给他的所有任务都完成了立马告知你。

创建Future

Future的几种创建方法

Future()
Future.microtask()
Future.sync()
Future.value()
Future.delayed()
Future.error()

其中sync是同步方法,任务会被立即执行

import  'dart:async';void  main() {
    print("main start");new  Future.sync((){
    print("sync task");
});new  Future((){
    print("async task");
});print("main stop");
}

运行结果:

main start
sync task
main stop
async task
注册回调

使用then注册回调

当Future中的任务完成后,我们往往需要一个回调,这个回调立即执行,不会被添加到事件队列。

import 'dart:async';void main() {
    print("main start");Future fut =new Future.value(18);// 使用then注册回调fut.then((res){
    print(res);});// 链式调用,可以跟多个then,注册多个回调new Future((){
    print("async task");}).then((res){
    print("async task complete");}).then((res){
    print("async task after");});print("main stop");
}

运行结果:

main start
main stop
18
async task
async task complete
async task after

除了then方法,还可以使用catchError来处理异常,如下

  new Future((){
    print("async task");}).then((res){
    print("async task complete");}).catchError((e){
    print(e);});

还可以使用静态方法wait 等待多个任务全部完成后回调。

import 'dart:async';void main() {
    print("main start");Future task1 = new Future((){
    print("task 1");return 1;});Future task2 = new Future((){
    print("task 2");return 2;});Future task3 = new Future((){
    print("task 3");return 3;});Future fut = Future.wait([task1, task2, task3]);fut.then((responses){
    print(responses);});print("main stop");
}

运行结果:

main start
main stop
task 1
task 2
task 3
[1, 2, 3]

如上,wait返回一个新的Future,当添加的所有Future完成时,在新的Future注册的回调将被执行。

async 和 await

在Dart1.9中加入了async和await关键字,有了这两个关键字,我们可以更简洁的编写异步代码,而不需要调用Future相关的API。他们允许你像写同步代码一样写异步代码和不需要使用Future接口。

将 async 关键字作为方法声明的后缀时,具有如下意义

被修饰的方法会将一个 Future 对象作为返回值
该方法会同步执行其中的方法的代码直到第一个 await 关键字,然后它暂停该方法其他部分的执行;
一旦由 await 关键字引用的 Future 任务执行完成,await的下一行代码将立即执行。

// 导入io库,调用sleep函数
import 'dart:io';// 模拟耗时操作,调用sleep函数睡眠2秒
doTask() async{
    await sleep(const Duration(seconds:2));return "Ok";
}// 定义一个函数用于包装
test() async {
    var r = await doTask();print(r);
}void main(){
    print("main start");test();print("main end");
}

运行结果:

main start
main end
Ok

注意:需要注意,async 不是并行执行,它是遵循Dart 事件循环规则来执行的,它仅仅是一个语法糖,简化Future API的使用。

总结

Future中的then并没有创建新的Event丢到Event Queue中,而只是一个普通的Function Call,在FutureTask执行完后,立即开始执行

当Future在then函数已经执行完成了,则会创建一个task,将该task的添加到microtask queue中,并且该任务将会执行通过then传入的函数

Future只是创建了一个Event,将Event插入到了Event Queue的队尾

Future.value创建Task到microtask Queue中执行then传入的函数

Future.sync执行了它传入的函数之后,也会立即创建Task丢到microtask Queue中执行

Future.wait等待多个任务全部完成后回调。wait返回一个新的Future,当添加的所有Future完成时,在新的Future注册的回调将被执行。

Future.delayed在延时一定时间后向队列插入一个任务
虽然可以预测任务执行的顺序,但是我们无法预测事件循环什么时候会从队列中提取任务。Dart事件处理系统基于单线程循环,而不是基于时基(tick,系统的相对时间单位)或者其他的时间度量。例如,当你创建一个延时1s的任务,1s后向事件队列添加一个任务,但在该任务之前的任务结束前,事件循环是不会处理这个任务的,也就是说该任务执行可能是大于1s的。

  相关解决方案