异步编程

异步编程是每个编程语言都会遇到的场景,比如我们从url请求数据,这个过程是耗时的,拿完数据还要做其他逻辑,整个过程就是异步编程的一种场景。

很多古老的语言,比如JavaScript和Java,都采用Callback的方式处理,以JavaScript代码为例:

function getData(url, callback) {
    let data = "data from url"; //获取数据
    callback(data);
}
getData("https://lixiaojun.xin", function (data) {
   console.log(data); 
});

Callback的方式问题就是当异步逻辑复杂后,会陷入回调地域。就算你层层抽取,代码的可读性依然很差。很多语言吸取Callback的教训,采取现代化的方式来处理异步,比如Kotlin用协程处理异步,JavaScript的ES 6版本和Python 3都使用了async/await来处理异步,Dart的方案也是async/await

async/await的好处是使用使用简单,能够使用同步写法编写异步代码。

异步方法

在方法后面增加async关键字,该方法就变成异步方法:

//该方法从传入的url读取数据
Future<String> requestData(String url) async{
  var data = "I am data from url"; //模拟从url请求数据的耗时操作
  return data;
}

async方法的返回值必须是Future类型,它表示将来某个时间会返回结果。如果一个异步方法确实不需要返回数据,可以将返回值设置为Future<void>

再编写一个方法来调用上面的异步方法,由于requestData()方法是耗时且异步的,需要使用await来等待结果返回,而await只能用在async方法中,需要再定义一个异步方法:

Future<void> printData() async{
  var data = await requestData("https://lixiaojun.xin");
  print(data);
}
main(){
  printData(); // I am data from url
}

当异步逻辑复杂,需要进行一连串的异步操作时,它看起来像这样:

Future<void> printData() async{
  var htmlData = await requestData("https://lixiaojun.xin"); //拿数据
  var data = await parseData(htmlData); //解析数据
  await saveData(data); //保存数据
  print(data);
}

可以看到代码依然很清晰,可读性一点也没有减少。在async/await的帮助下,我们可以轻松编写大型的异步程序,代码的可维护性也非常高。

等待多个Future

有时候我们的逻辑需要在多个异步操作都执行完毕之后才往下进行,可以使用Future.wait()方法等待多个Future完成,代码如下:

Future doThing1() async{
  print("doThing1");
  return Future.delayed(Duration(seconds: 1));
}
Future doThing2() async{
  print("doThing2");
  return Future.delayed(Duration(seconds: 2));
}
Future doThing3() async{
  print("doThing3");
  return Future.delayed(Duration(seconds: 3));
}

main() async{
  await Future.wait([doThing1(), doThing2(), doThing3()]);
  print("all things is done!!!");
}
//输出
doThing1
doThing2
doThing3
//等待3秒钟输出    
all things is done!!!

注意:Future.wait()中的任务是并发执行的。

异步异常处理

Dart的异步异常的处理方式和正常的同步代码并没有什么区别,使用try..catch在可能抛出异常的地方进行捕获即可。

修改上面的doThing3()方法,增加抛出异常的代码:

Future doThing3() async {
  print("doThing3");
  throw "thing3 occur error";
  return Future.delayed(Duration(seconds: 3));
}

然后在调用处进行捕获:

main() async {
  try {
    await Future.wait([doThing1(), doThing2(), doThing3()]);
    print("all things is done!!!");
  }catch (e){
    print("异步操作出现了异常");
  }
}
//输出
doThing1
doThing2
doThing3
异步操作出现了异常

运行程序,可以成功的捕获到异常,并不会导致程序崩溃。

更新时间: 5/6/2019, 11:32:40 AM