
5.2 异步处理
众所周知,诸如Word等软件都有自动保存的功能,这一功能自动完成且不会打断工作。这实际上就是异步处理的体现,我们可以借助Dart编程语言轻松实现类似的功能。在实际开发过程中,它通常用于网络请求、本地文件的输入和输出等。
在Dart中,通常返回Future对象或Stream对象的方法就是异步方法。当执行这样的方法时,会立即得到返回,而真正想要的结果会在相应的Future对象或Stream对象中获得。下面我们就来模拟真实的情况,体验一下Dart中的异步处理机制。我们可以使用dart.io中的sleep()方法让主线程休眠,达到模拟某些耗时操作的目的。具体代码片段如下:

运行,输出结果:

可见,主线程确实卡住了2秒,而“后面的逻辑”也将被迫等待着2秒结束才能运行,这通常不是我们希望的结果。下面看一下使用异步线程优化的结果:

再回到main()方法中调用:

运行,输出结果:

可见,后面的逻辑照常运行,由于耗时操作不会在主线程中运行。
5.2.1 声明异步的方法
对于上述代码,如果去掉模拟耗时的部分,实际上就是输出一个字符串。在非异步运行时,输出一个字符串的方法很简单,如下所示:

对比异步运行的写法:

注意:返回类型和async关键字的使用。
5.2.2 使用await表达式
await表达式的结构:

在上一小节中使用printStr()方法时,如下:

在使用await表达式时,还可以按下面的方法嵌套使用:

在上面的代码中,functionA(),functionB()和functionC()会被依次执行并返回结果。如果在main()方法中使用await表达式,同样要给main()方法加上async关键字。以上便是使用await和async关键字声明和实现异步的方法,在实际开发中通常用于网络HTTP请求。
5.2.3 异步在循环中的使用
除了上述实际使用场景,还有一些具有持续性特征的数据需要进行异步处理,这在实际开发中同样很多见。比如,下载或上传一个大文件。此时,就需要将异步放置在循环中,并使用await for关键字。其结构如下:

在上述结构中,表达式的返回值需要是Stream类型。在运行时,首先等待表达式返回值,通常这个返回值在循环体中被使用。然后继续等待,重复执行上述过程。最后直到Stream再无返回值为止。例如,在下载一个大文件时,如2GB的文件,通常会将这个大文件分成若干个小文件下载,然后合在一起还原文件本来的样子,而这若干个小文件就可以使用上述循环进行下载。