Firebase getDocument是否逐行运行? [英] Is Firebase getDocument run line by line?

查看:88
本文介绍了Firebase getDocument是否逐行运行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是一位敏捷而Firebase的初学者,我遇到了一个使我非常困惑的问题.我们都知道以下代码

I'm a swift and Firebase beginner, I met a problem that confuses me a lot. We all know the following code

var a = [Int]()
for i in 0..2{
    a.append(i)
    print(a)
print(a)

应该给我输出

[0]
[0,1]
[0,1,2]
[0,1,2]

结果是正确的.但是,当我使用getDocument()并编写类似的逻辑代码时,输​​出结果很奇怪!代码如下.

And it is true as the result. However, when I work on getDocument(), and I write a similar logic code, the output is strange! The code is the following.

override func viewDidLoad() {
    super.viewDidLoad()
    let docSecond = getThirtyData()
    getDataContent(thirtyData: docSecond)
}
func getThirtyData()->Array<Int>{
    var querySecond = [Int]()
    var docSecond = [Int]()
    let postDoc = db.collection("announcement")
    postDoc.getDocuments { (querySnapshot, err) in
        if let err = err{
            print("Error getting documents: \(err)")
        }else{
            for document in querySnapshot!.documents{
                //print(document.data()["postTimeSecondInt"] as! Int)
                querySecond.append(document.data()["postTimeSecondInt"] as! Int)
            }
            for _ in 1...querySecond.count{
                let max = querySecond.max()!
                docSecond.append(max)
                let index = querySecond.firstIndex(of: max)
                querySecond.remove(at: index!)
            }
            print(docSecond)
            print("123")
        }
    }
    print(docSecond)
    print("456")
    return docSecond
}

func getDataContent(thirtyData: [Int]){
    print(thirtyData)
    print("789")
}

我认为结果可能是相同的逻辑,即先打印"123",然后打印"456",再打印"789".但是,结果如下所示.

I thought the result might come as same logic which is "123" print first, then "456", then "789". However, the result is like below.

[]
456
[]
789
[1588428987, 1588428980, 1588427392]
123

似乎它与for循环同时运行下面的代码行.谁能解释为什么会这样?

Seems like it run the code line below simultaneously with the for loop. Can anyone explain why this happens?

推荐答案

这已按预期/已记录在案,但如果您从未使用过异步API,的确会造成混淆.代码乱序执行的原因是 postDoc.getDocuments()必须从服务器读取数据,这可能需要一些时间.除了阻止您的代码(从而阻止用户使用您的应用)之外,您还可以继续执行您的主要代码.然后,当从服务器上获得数据时,将使用该数据调用完成处理程序.

This is working as intended/documented, but if you've never used an asynchronous API it can indeed be confusing. The reason that the code executes out of order is that postDoc.getDocuments() has to read data from the server, which may take time. Instead of blocking your code (and thus keeping the user from using your app), your main code is allowed to continue. And then when the data is available from the server, your completion handler is called with that data.

最简单的方法是添加一些日志记录语句:

It's easiest to see this by adding some logging statements:

print("Before starting to load data")
let postDoc = db.collection("announcement")
postDoc.getDocuments { (querySnapshot, err) in
    print("Got data");
}
print("After starting to load data")

运行此最小代码时,它会打印:

When you run this minimal code, it prints:

开始加载数据之前

Before starting to load data

开始加载数据后

获得数据

这可以按预期工作,但是如果您从未使用过异步或事件驱动的API,则确实非常令人困惑.不幸的是,大多数现代的云/Web API是异步的,因此最好习惯这种模式.希望我上面的解释对此有所帮助.

This is working as intended, but indeed very confusing if you've never worked with asynchronous or event driven APIs yet. Unfortunately most modern cloud/web APIs are asynchronous, so it's best to get used to this pattern. Hopefully my explanation above help a bit for that.

要记住的两件重要事情:

Two important things to remember:

  • 您的 print(docSecond)无法打印所需的数据,因为 docSecond.append(max)尚未运行.
  • 任何需要数据库中数据的代码都必须位于用该数据调用(或从那里调用)的完成处理程序中.
  • Your print(docSecond) doesn't print the data you want, because docSecond.append(max) hasn't run yet.
  • Any code that needs data from the database, needs to be inside the completion handler that is called with that data (or be called from there).

您不能返回异步加载的数据.典型的解决方法是创建一个自定义完成处理程序,与Firestore的 getDocuments() postDoc.getDocuments {(querySnapshot,err)中接受的完成处理程序非常相似,但随后使用您自己的类型.

You can't return data that is loaded asynchronously. The typical workaround is to create a custom completion handler, very similar to the completion handler that Firestore's getDocuments() accepts postDoc.getDocuments { (querySnapshot, err) in, but then with your own type.

类似的东西:

func getThirtyData(_ completion: (Array<Int>) -> ()) {
    var querySecond = [Int]()
    var docSecond = [Int]()
    let postDoc = db.collection("announcement")
    postDoc.getDocuments { (querySnapshot, err) in
        if let err = err{
            print("Error getting documents: \(err)")
        }else{
            for document in querySnapshot!.documents{
                querySecond.append(document.data()["postTimeSecondInt"] as! Int)
            }
            for _ in 1...querySecond.count{
                let max = querySecond.max()!
                docSecond.append(max)
                let index = querySecond.firstIndex(of: max)
                querySecond.remove(at: index!)
            }
            completion(docSecond)
        }
    }
}

然后像这样调用它:

getThirtyData { docSecond in
   getDataContent(thirtyData: docSecond)
}

另请参阅:

这篇关于Firebase getDocument是否逐行运行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆