我有一系列键,可以为我的社交网络提供帖子对象,例如/posts/id/(post info)
当我加载帖子时,我使用 observeSingleEventOfType(.Value)
方法加载/posts/0,然后加载/posts/1 等。
我使用lazyTableView
一次加载 30 个,而且速度很慢。有什么方法可以使用其中一种查询方法或其他方法使其更快,即使我必须重组 JSON 树中的数据。
我来自 Parse 重新实现我的应用程序,到目前为止,体验非常好。只是一件事我有点坚持。
编辑:
func loadNext(i: Int) {
// check if exhists
let ideaPostsRef = Firebase(url: "https://APPURL")
ideaPostsRef.childByAppendingPath(i.description).observeSingleEventOfType(.Value, withBlock: {
(snapshot) in
if i % 29 == 0 && i != 0 && !self.hitNull { return }
// false if nil
// true if not nil
if !(snapshot.value is NSNull) {
let postJSON = snapshot.value as! [String: AnyObject]
print("GOT VALID (postJSON)")
let post = IdeaPost(message: postJSON["message"] as! String, byUser: postJSON["user"] as! String, withId: i.description)
post.upvotes = postJSON["upvotes"] as! Int
self.ideaPostDataSource.append(post)
self.loadNext(i + 1)
} else {
// doesn't exhist
print("GOT NULL RETURNING AT (i)")
self.doneLoading = true
self.hitNull = true
return
}
}
}
这个递归函数本质上是从 firebase 获取键号 i 的值。如果是 NSNULL,它知道这是最后一个可能加载的帖子,并且再也不会这样做了。如果 NSNULL 没有被命中但i % 29 == 0
则它作为基本情况返回,因此一次只加载 30 个帖子(0 个索引)。当我将doneLoading
设置为 true
时,tableView.reloadData()
是使用属性观察器调用的。
这是我正在获取的数组
的示例"ideaPosts" : [ {
"id" : 0,
"message" : "Test",
"upvotes" : 1,
"user" : "Anonymous"
}, {
"id" : 1,
"message" : "Test2",
"upvotes" : 1,
"user" : "Anonymous"
} ]
更新:我们现在也在AskFirebase剧集中讨论这个问题。
从 Firebase 加载许多项目不一定很慢,因为您可以管道处理请求。但是您的代码使这变得不可能,这确实会导致性能欠佳。
在代码中,从服务器请求一个项,等待该项返回,然后加载下一个项。在简化的序列图中,如下所示:
Your app Firebase
Database
-- request item 1 -->
S L
e o
r a
v d
e i
<- return item 1 -- r n
g
-- request item 2 -->
S L
e o
r a
v d
e i
r n
<- return item 2 -- g
-- request item 3 -->
.
.
.
-- request item 30-->
S L
e o
r a
v d
e i
r n
g
<- return item 30 --
在此方案中,等待的往返时间是 30 倍 + 从磁盘加载数据所需时间的 30 倍。如果(为简单起见)我们说往返需要 1 秒,从磁盘加载项目也需要一秒,至少到 30 * (1 + 1) = 60 秒。
在Firebase应用程序中,如果您一次性发送所有请求(或至少合理数量的请求),您将获得更好的性能:
Your app Firebase
Database
-- request item 1 -->
-- request item 2 --> S L
-- request item 3 --> e o
. r a
. v d
. e i
-- request item 30--> r n
g
<- return item 1 --
<- return item 2 --
<- return item 3 --
.
.
.
<- return item 30 --
如果我们再次假设往返 1 秒和加载时间为 1 秒,则您正在等待 30*1 + 1 = 31 秒。
所以:所有请求都通过同一个连接。鉴于此,get(1)
、get(2)
、get(3)
和getAll([1,2,3])
之间的唯一区别是帧的一些开销。
我设置了一个 jsbin 来演示该行为。数据模型非常简单,但它显示了差异。
function loadVideosSequential(videoIds) {
if (videoIds.length > 0) {
db.child('videos').child(videoIds[0]).once('value', snapshot => {
if (videoIds.length > 1) {
loadVideosSequential(videoIds.splice(1), callback)
}
});
}
}
function loadVideosParallel(videoIds) {
Promise.all(
videoIds.map(id => db.child('videos').child(id).once('value'))
);
}
相比之下:在我的系统上按顺序加载 64 个项目需要 3.8 秒,而通过管道加载它们(就像 Firebase 客户端本机加载一样)需要 600 毫秒。确切的数字将取决于您的连接(延迟和带宽),但流水线版本应始终明显更快。