前言

这段时间在学习一些Dart的语法,学到有关异步编程这一块,也许是受之前学过的Java/PHP/C++的影响,就感觉Dart的异步特别别扭,花了好一段时间才算是搞清楚大概是怎么回事,于是在此做下笔记。

正文

async和await的一些规则:

  • await关键字必须在被async声明的方法中使用,await可以对同一表达式or函数使用多次(一般一次就够了,只是语法上没有限制)。
  • async修饰的方法返回值是Future类型,在没有await关键字声明调用时,无法自动转换成基本类型or自定义类型。
  • async修饰的方法会同步执行完第一个await关键字的代码行,然后暂停这一行后面的代码,之后再拿出来执行,可以当做后面的代码都压入了某个“栈”中。
  • 虽说async和await关键字组合在Dart中被称为异步编程,但模式是同步非阻塞,即任务仍然是在同一个线程中完成的,不会创建新线程。

先来看几个简单的async例子,之后再说概念感觉好理解一些:

第一个例子

main() {
  create();
}

void create() async {
  getData1();
  getData2();
  print("5");
}

void getData1() async {
  print("1");
  print("2");
}

void getData2() async {
  print("3");
  print("4");
}

输出结果:

1
2
3
4
5
  • 老实说上面的例子加不加async其实没什么不同,但实际上加了async关键字的方法如果有返回值的话,返回的类型是Future,这点稍后举个例子,这个例子这么写主要还是为了避免下面例子被返回值模糊了。

第二个例子

main() {
  create();
}

void create() async {
  getData1();
  getData2();
  print("5");
}

void getData1() async {
  await print("1");
  print("2");
}

void getData2() async {
  print("3");
  print("4");
}

输出结果:

1
3
4
5
2

这里发现getData1()的一行加了await,结果输出结果顺序就变成了1,3,4,5,2,原因如下:

  • async修饰的方法会同步执行完第一个await关键字的代码行,然后暂停这一行后面的代码,之后再拿出来执行。

第三个例子

main() {
  create();
}

void create() async {
  getData1();
  getData2();
  print("5");
}

void getData1() async {
  await print("1");
  print("2");
}

void getData2() async {
  await print("3");
  print("4");
}

输出结果:

1
3
5
2
4

这里在第二个例子的基础上,我们在getData2()中也加了await,于是输出结果就变成了1,3,5,2,4,原因如下:

  • 程序首先执行create()
  • 执行getData1(),并遇到第一个await关键字,于是执行print("1"),此时控制台输出1,然后把剩下的print("2")放入待执行的栈中。
  • 返回并执行getData2(),并遇到第一个await关键字,于是执行print("3"),此时控制台输出3,然后把剩下的print("4")放入待执行栈中。
  • 返回并执行print("5"),此时控制台输出5,之后发现栈中还有东西没执行,于是获取栈顶元素,执行print("2"),控制台输出2,继续获取栈顶元素,执行print("4"),控制台输出4,栈顶为空,整个main方法就结束了。

第四个例子

这个例子主要说明async返回值的问题

main() {
  create();
}

void create() async{
   String data = getData();
   print(data);
}

getData() async{
  return "1";
}

以上代码会报错:

Uncaught Error: TypeError: Instance of '_Future<dynamic>': type '_Future<dynamic>' is not a subtype of type 'String'

原因就是开头说的,更正方式也很简单:

main() {
  create();
}
void create() async {
   String data = await getData();
   print(data);
}
getData() async {
  return await "1";
}