「google教程」async/await的使用和原理

文章授权首发于code4flutter,如需转载请注明来源 https://code4flutter.com/async-await-usage/
本文是flutter油管教程第3篇,介绍async和await的使用和原理
引言
很多语言使用async和await作为语法,将函数变成async,然后在代码的某个位置,它会进行等待,直到任务处理完成返回 。在flutter中也是这样的基本功能,但是需要特别指出的是这种语法糖只是feature和stream的封装,可以让你更清晰的更易读的代码 。
对比

「google教程」async/await的使用和原理

文章插图
 
这里是一个处理数据处理的例子,网络请求和文件IO操作是异步操作
我们想让他们放在一起工作,首先通过网络请求创建一个id,根据这个id进行网络通信,然后用结果创建一个processdata的对象,使用dart的feature的api,然后将回调链接在一起 。这样用前一个的回调作为下一个回调的参数输入,以此类推 。但是之前的方式并不具有很好的可读性,需要层层嵌套,但是用feature结合async和wait不一样 。
ProcessedData createData() async{ final id = _loadFromDisk(); final data = https://www.isolves.com/it/cxkf/bk/2019-11-20/_fetchNetworkData(id); return ProcessedData(data);}复制代码首先,添加async关键字,只是告诉编译器,“嘿,我打算在这里使用await关键字”
接下来我们来添加await关键字,在每个feature之前,标志需要等待的函数,
最后,在返回值添加feature关键字,有人觉得很奇怪,为什么只是普通的返回处理数据结果的函数需要feature修饰呢,这是因为在processData之前有两次异步操作用到了await 。这意味着他开始执行,然后停止,等待磁盘事件,然后继续,然后停下来等待网络事件 。只有在那之后才能提供一个值 。代码如下:
ProcessedData createData() async{ final id = await _loadFromDisk(); final data = https://www.isolves.com/it/cxkf/bk/2019-11-20/await _fetchNetworkData(id); return ProcessedData(data);}复制代码asyc/await 工作原理
所以当createData开始运行并触发第一个await时,他才会返回一个feature,到调用函数,他说,“嘿,我需要等待一下东西”,这是一个空盒子,你需要等待一会儿,当我在网络中等待的磁盘数据到达时,我将调用return语句并为你提供一些数据,把它放入futurebuilder,或其他东西中,这就是他的工作原理 。用代码翻译如下:
Future<ProcessedData> createData(){ return _loadFromDisk().then((id){ return _fetchNetworkData(id);}).then((data){ return ProcessData(data);})}复制代码用feature api的好处就是你可以清楚的看到代码是如何将事件进行拆分的 。首先函数开始执行,调用loadfromdisk,等待来来自磁盘的数据触发事件循环,然后第二个回调被调用,请求网络,等待来自网络的数据到达事件循环,然后处理数据 。此时调用return,此时该值完成了 。
「google教程」async/await的使用和原理

文章插图
事件循环
现在我们使用async/await版本实现 。通过await表达式作为等待 。由此可以得到以下代码 。
async/await正确姿势
Future<ProcessedData>createData() async{ final id = await _loadFromDisk(); final data = https://www.isolves.com/it/cxkf/bk/2019-11-20/await _fetchNetworkData(id); return ProcessedData(data);}复制代码createData开始执行,并触发第一个等待,此时它将自己的future返回给函数,并调用loadFromDisk,然后像之前一样,等待来自磁盘文件I/O事件,这样就完成了由loadFromDisk返回的future,这意味着createData结束了等待,并可以继续执行其余的代码了 。再次等待,请求网络数据等待返回,最终网络数据到达事件循环,这就完成了由fetchNetworkData返回的future 。createData就可以再次继续运行了,他创建并返回了一个ProcessedData的实例 。他完成了createData在开头处传给调用者的那个future 。
由此可以看到,相同的事件循环控制着代码的运行,并涉及到相同的future,唯一变化的是,有了async/await,函数代码变少了,看起来更像是同步的代码 。
async/await如何处理错误
普通的写法,处理错误如下,
「google教程」async/await的使用和原理

文章插图
 
使用catcherror来处理错误,完成后悔在最后执行回调,无论是否有错误发生 。
【「google教程」async/await的使用和原理】在aync/await的方式中不用任何回调,而是用try catch
「google教程」async/await的使用和原理

文章插图
 
可以使用try catch捕获特定类型的异常,finally将在最后执行其代码块 。


推荐阅读