![Flutter从0基础到App上线](https://wfqqreader-1252317822.image.myqcloud.com/cover/259/33831259/b_33831259.jpg)
5.2 异步处理
众所周知,诸如Word等软件都有自动保存的功能,这一功能自动完成且不会打断工作。这实际上就是异步处理的体现,我们可以借助Dart编程语言轻松实现类似的功能。在实际开发过程中,它通常用于网络请求、本地文件的输入和输出等。
在Dart中,通常返回Future对象或Stream对象的方法就是异步方法。当执行这样的方法时,会立即得到返回,而真正想要的结果会在相应的Future对象或Stream对象中获得。下面我们就来模拟真实的情况,体验一下Dart中的异步处理机制。我们可以使用dart.io中的sleep()方法让主线程休眠,达到模拟某些耗时操作的目的。具体代码片段如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt005_10.jpg?sign=1734398591-MOF5sl0kycbJBl5axqfX71Mi68NYscTK-0-e7438d6e471503c7172dcf0ce0e844b0)
运行,输出结果:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt005_11.jpg?sign=1734398591-NGgOJpeyoi7Z6glB6Qh6FT0szxmtYA2u-0-88a2f52c05334675fd6f926ade9e887c)
可见,主线程确实卡住了2秒,而“后面的逻辑”也将被迫等待着2秒结束才能运行,这通常不是我们希望的结果。下面看一下使用异步线程优化的结果:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt005_12.jpg?sign=1734398591-8apTO3x8ez4Nrx75ijbzjZ0EOqQtNLyT-0-aec76873a00d8b65d00505b2eb1e022a)
再回到main()方法中调用:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt005_13.jpg?sign=1734398591-FJn6UcmQivOpUWp4v2E9LX44kuKIRYTi-0-aa3a6eab8582e4b6b1681867c10120ff)
运行,输出结果:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt005_14.jpg?sign=1734398591-53qeyUPGIEqkT12YwA42AkfJ3VYA2FZD-0-e84685b364518fb7e7d278ecb9f53e47)
可见,后面的逻辑照常运行,由于耗时操作不会在主线程中运行。
5.2.1 声明异步的方法
对于上述代码,如果去掉模拟耗时的部分,实际上就是输出一个字符串。在非异步运行时,输出一个字符串的方法很简单,如下所示:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt005_15.jpg?sign=1734398591-TB5vUwapUF8nuw65lYzKsY1erzDI58sx-0-62b7b16ff235dc3c5e821cc087946090)
对比异步运行的写法:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt005_16.jpg?sign=1734398591-E1bm9EJ26Ac1xqqvjnGPByz0hrkCmPLc-0-ff6481176eb21ffdb001f16ec1d5db55)
注意:返回类型和async关键字的使用。
5.2.2 使用await表达式
await表达式的结构:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt005_17.jpg?sign=1734398591-YI7TwZ0kRrhTTR7IvI3F1zAFORPcdpp8-0-3bf770f2938b311e0052e83151f06d72)
在上一小节中使用printStr()方法时,如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt005_18.jpg?sign=1734398591-EtZYhO2lkFiuuZJDYj7Lb2kd4drbEwz9-0-89370e837f0cd5505e8b92224c6842dd)
在使用await表达式时,还可以按下面的方法嵌套使用:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt005_19.jpg?sign=1734398591-fjvszySQOqgb1OXBOlyPpnpOYawpkMdn-0-1dd0f610d88988bf3c849fde21597635)
在上面的代码中,functionA(),functionB()和functionC()会被依次执行并返回结果。如果在main()方法中使用await表达式,同样要给main()方法加上async关键字。以上便是使用await和async关键字声明和实现异步的方法,在实际开发中通常用于网络HTTP请求。
5.2.3 异步在循环中的使用
除了上述实际使用场景,还有一些具有持续性特征的数据需要进行异步处理,这在实际开发中同样很多见。比如,下载或上传一个大文件。此时,就需要将异步放置在循环中,并使用await for关键字。其结构如下:
![img](https://epubservercos.yuewen.com/9CF474/18096059801207706/epubprivate/OEBPS/Images/txt005_20.jpg?sign=1734398591-VaU9ARlinx8mDG6clWZCGsf0rv4AT0Qe-0-48b17ea91535f6afe31c0f54f0ddaca7)
在上述结构中,表达式的返回值需要是Stream类型。在运行时,首先等待表达式返回值,通常这个返回值在循环体中被使用。然后继续等待,重复执行上述过程。最后直到Stream再无返回值为止。例如,在下载一个大文件时,如2GB的文件,通常会将这个大文件分成若干个小文件下载,然后合在一起还原文件本来的样子,而这若干个小文件就可以使用上述循环进行下载。