Swift:如何仅在前一个异步函数完成后才执行异步函数

问题描述 投票:0回答:1

我有一个函数,它依次执行四个函数。棘手的部分似乎是让它们以正确的顺序执行。 function1 完成后,我想执行 function2 和 function3,它们可以同时运行。当 function2 和 function3 都完成时,我想运行 function4。

考虑:

func initializeMe() {
    Task {
        await loadMyData()
        await loadMyLikes()
        await loadMyAdmirers()
        loadMyFriends()
    }
}

流程应该是:

  • loadMyData()
    从 Firestore 数据库加载用户数据,其中包含一个名为 likes 的数组,其中充满了用户 ID。

  • loadMyLikes()
    根据
    loadMyData()

    中加载的点赞数组从 Firestore 加载用户
  • loadMyAdmirers()
    也会加载用户,这次是在其他用户喜欢的地方寻找当前用户的id

  • loadMyFriends()
    查找
    myLikes
    myAdmirers
    共有的用户 ID。

并发对我来说很困难,我感觉我可能也需要这里的完成处理程序。任何建议将不胜感激。

swift async-await concurrency
1个回答
2
投票

如果您希望

loadMyLikes
loadMyAdmirers
同时运行,有两种常见模式。

  1. “任务组”,使用

    withTaskGroup
    ,或
    withDiscardingTaskGroup
    :

    func initializeMe() async {
        await loadMyData()
        await withDiscardingTaskGroup { [self] group in
            group.addTask { await loadMyLikes() }
            group.addTask { await loadMyAdmirers() }
        }
        loadMyFriends()
    }
    
  2. 使用

    async let

    func initializeMe() async {
        await loadMyData()
        async let likes: Void = loadMyLikes()
        await loadMyAdmirers()
        await likes
        await admirers
        loadMyFriends()
    }
    

这两者都会:

  • await loadMyData()
  • 完成后,同时运行
    loadMyLikes
    loadMyAdmirers
    ;和
  • 当这两个完成后,运行
    loadMyFriends

两个最终观察结果:

  • 就我个人而言,我会对在该函数中隐藏非结构化并发(

    Task {…}
    )持谨慎态度。调用者无法知道它何时完成。您也将失去取消的可能性。

    在上面,我将其设为

    async
    函数,如果我确实需要从非
    async
    上下文进行桥接,我个人会在调用
    initializeMe
    的地方执行此操作,而不是在这里。随意做任何你想做的事情,但要对隐藏非结构化并发的影响非常敏感(或者至少在不做保存
    Task
    的先决开销的情况下这样做,编写一些取消处理程序代码,弄清楚如何更新UI 与结果等)。

    这里根本没有足够的信息来为您提供有关此主题的进一步建议(并且超出了本问题的范围),但是,简而言之,请小心非结构化并发

  • 您显然将这些函数的结果存储在属性中。有时我们想这样做(以便我们可以在更新信息出现时观察数据变化),但通常我们不会这样做。

    例如,当

    loadMyData
    完成后,但我们还没有完成其他三个方法,UI 中要显示什么?没有点赞/崇拜者/朋友的数据?或者什么都不做,直到一切都完成?

    底线,另一种方法是以这样的方式编写这些函数:它们更新属性,而是

    return
    各自的结果。我们可以将其保存在局部变量中,并且仅在所有四种方法完成后才使用本地存储的结果更新属性。

    这完全取决于你,但我想至少让你注意这种替代方法。

© www.soinside.com 2019 - 2024. All rights reserved.