初识 async/await

WWDC21 推出了 async/await,特意去百度了一下:

微软在发布 VS2012 的同时推出了C# 5.0,其中包含了async和await。

Swift 也在进化,WWDC21 推出的 swift 5.5 也终于加入了 async/await 特性。下面是对 Meet async/await in Swift 的整理。如果有不恰当的地方,欢迎评论区交流。

如上图,列表中每一行左侧的小图标是从服务端下载下来并渲染到 UI 界面上来的。一般情况下远端图片下载渲染分以下四个步骤:
1、通过图片的地址 URL 地址创建一个 URLRequest 的对象;
2、以上一步创建的 URLRequest 对象为参,通过 URLSession 创建一个 task 任务用于请求远端的图片数据;
3、等待,异步获取 UIImage 的 data 数据, 然后将 data 通过 UIImage 的 initWithData 方法转化成 image 对象;
4、将该 image 对象渲染到 UI 界面;

IMG_0517.PNG

一个简单的异步获取数据并在 completion handler 中处理返回的数据,每位 iOS 开发者对这个过程并不陌生。其整的实现代码如下

IMG_0525.PNG

很熟悉的味道吧!

二十行代码左右,通常我们都会去这么实现或采用类似的实现方式。所谓习惯成自然,也就没觉着这样有什么不好。但可不可以更简洁点呢?

上面的写法不简洁吗?

是的!
相比 async/await 的实现方式,上面的代码有以下几个问题:
1、为了向通知外界返回的结果,completion 回调写了 5 次,而且很容易在两个guardelse 执行语句中漏写;
2、不直观,函数体若按上到下的顺序执行比较符合人们的阅读习惯,而且很清楚的表达了代码的意图。但这里图片的下载是异步的, dataTask 的尾随闭包里面的代码其实是后执行的;
3、代码多,容易乱,不够简洁;

现在 Swift 5.5 引入 async/await 特性。下面来使用 async/await 语法来实现上述功能。

分析一下这个实现:
先来看函数定义这一行,fetchThumbnail 参数的右括号后面紧跟了一个 async 关键字,表示该函数为 async 函数。async 后面则跟了个 throw 关键字,表示该函数可能会抛出错误。

函数体中第二行在获取图片时使用了 await 关键字,表示这是一个需要等待的操作,因为图片的下载因网络好坏需要不确定的时间。此时函数执行到这里会暂停(suspend),但不会阻塞程序的执行,系统会接管该函数所在的线程去继续执行其它的任务。待图片下载完成之后,系统又会回到这个暂停的地方,该函数会 resume 从而继续执行下面的函数语句

接下来是处理返回数据。若返回的数据的 statusCode 不等于 200 ,说明请求不成功,使用 throw 抛出错误。反之将返回的数据 data 转化为 UIImage 对象。在数据转换过程中如果发生异常,同样由 throw 抛出错误,否则就返回处理好的 thumnail 对象供渲染使用。

至此, async/await 版的代码完成了上面传统的 completion handler 回调函数完成的图片下载。代码量简洁,逻辑更清晰,代码可读性幅提高!都忍不住想来一句:good job !

回过头再去仔细看一下这个函数实现。倒数第二行乍一看上去不是一个异步函数,但仍然使用了 await 关键字,这不科学!其实不然,这里的 thmbnail 其实是一个 async 类型的属性(property)。

注意:仅 read-only 类型的 property 才可以是标记为 async。

不仅 functionpropertyinitializer 也可以标记为 async。那么还有没有其它的呢?有,下面有请 AyncSequence 登场!

AsyncSequence 是一个可以异步获取其元素的一个序列。由于其每一个元素的获取都是异步的,所以依次获取其中的每一个元素都是 awaitable 的,需要使用 await 关键字进行标识。

综上,有很多地方你可以使用 await 关键字,await 也表示一个 async 标识的函数执行到这里时候会暂停 suspend。那这里的暂停 suspend 意味着什么呢?

通常情况下,当我们调用一个函数的时候,函数体的执行在执行完之前会一直占用当前的线程,直到函数体执行完毕之后当前线程才能去执行其它的任务。而 async 函数就不一样了,它具有 暂停 suspend 的能力。当暂停时,它就会让出当前线程给系统,由系统去决定当前线程去执行其它任务。而且 async 函数可以暂停 suspend 多次。当标识为 await 的任务完成之后,系统又会重新回到原来暂停的地方,原来的函数被 resume 接着执行函数体下面的代码。需要注意的是,被 resume 的函数所处的线程可能与之前 suspend 时所处的线程不是同一个线程。

async 函数的执行流程

async 函数的执行流程

理论和示例都看过了,问题来了:怎样将现有的代码切换为 async/await 呢?

先从现代软件编码的一个重点代码测试开始。我们想像测试同步代码一样方便的去测试异步代码,于是 async/await 就派上用场了!

下面是一个通常情况下的测试异步代码的一个示例

使用 async/await 特性之后

不仅如此,当前很多的系统库 API 也都支持了 async/await 这一特性。
比如

代理方法中也有不少 completion handler 语法,当然我们没有忘记。同样代理方法你也可以选择使用 async/await 特性的 API。

到这里,你所看到的所有异步函数都是 Swift 帮你实现的,你只要使用就行了。但总有一些情形需要你自己去搞定异步函数。于是就有了 continuation 。借助 continuation,你可以灵活的自己去决定异步函数 resume 的时机和位置。

如上,借助 withCheckedThrowingContinuation 你可以向上面这样使用 continuations 。

使用 continuation 需要注意两点:
1、continuation 不能被丢弃,必须要执行相关操作以唤醒之前 suspend 的异步函数;
2、continuationresume 函数在一个分支条件上只能调用一次;

Thanks for reading!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容