# 【补】异步编程

Dart与JavaScript的共同点是单线程,同步代码会阻塞程序。因此程序中会看到大量异步操作,使用Future对象来执行相关操作,并且在async函数使用await关键字是才执行,直到一个Future操作完成。Future支持链式操作,可以按顺序执行异步函数。

# Future是什么

一个Future是一个Future自身泛型Future<T>对象,表示一个异步操作产生得T类型结果。如果结果值不可用,Future的类型会是Future<void>,如果返回一个Future的函数被调用将会发生:

  1. 这个函数加入待完成队列并且返回一个未完成的Future对象
  2. 当这个操作结束,Future对象返回一个值或错误

Future的几种创建方法:

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

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

Future<int> future = getFuture();
future.then((value)=>handleValue(value))//接受异步处理结果
      .catchError((error)=>HandleError(value))//在异步函数中捕获异常
      .whenComplete()=>handleCpmplete();//无论处理成功还是失败,之后如需还需要处理些事,可以在whenComplete中进行

# async和await

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

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

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

但遇到有需要延迟的运算(async)时,将其放在延迟运算队列(await)里,把不需要延迟运算的部分先执行完,最后再处理延迟运算的部分。但是要是用await,就必须在有async的标记的函数里执行,否则这个await会报错。

与JavaScript很像,asyncawait是Future的语法糖(Syntactic sugar),解决回调地狱(Callback Hell)问题。

举一例:

step1('step1').then((step1Result){
    step2(step1Result).then((step2Result){
        step3(step3Result).then((step3Result){
            // ...  
        });
    });
});

使用async-await改写之后:

steps() async{
    try{
        String step1Result = await step1('step1');
        String step2Result = await step1(step1Result);
        String step3Result = await step1(step1Result);
        //...
    }catch(error){
        print(error);
    }
}
  • 当使用async作为方法名后缀声明时,说明这个方法的返回值是一个Future;
  • 当执行到该方法代码用await关键字标注时,会暂停该方法其他部分执行;
  • 当await关键字引用的Future执行完成,下一行代码会立即执行。