web-dev-qa-db-fra.com

Accélérer la récupération des publications pour mon application de réseau social en utilisant une requête au lieu d'observer un seul événement à plusieurs reprises

J'ai un tableau de clés qui permet de poster des objets pour mon réseau social, comme so/posts/id/(post info)

Quand je charge les posts, je charge/posts/0 puis/posts/1 etc. en utilisant la méthode observeSingleEventOfType(.Value).

J'utilise un lazyTableView pour charger 30 à la fois et c'est assez lent. Existe-t-il un moyen d'utiliser une des méthodes de requête ou un autre moyen de le rendre plus rapide même si je dois restructurer les données dans mon arborescence JSON?.

Je viens de Parse ré-implémenter mon application et jusqu'à présent, l'expérience a été plutôt bonne. Juste une chose sur laquelle je suis un peu coincé. Merci d'avance pour l'aide!

EDIT:

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
        }
    }
}

Cette fonction récursive s'exécute essentiellement en obtenant la valeur du numéro de clé i à partir de firebase. Si c'est NSNULL, il sait que c'est la dernière publication possible à charger et ne le fait plus jamais. Si NSNULL n'est pas touché mais i % 29 == 0, Il est renvoyé comme scénario de base, de sorte que seuls 30 messages sont chargés à la fois (0 indexé). Lorsque je règle doneLoading sur true, tableView.reloadData() est appelée à l'aide d'un observateur de propriétés.

Voici un exemple de la matrice que je vais chercher

"ideaPosts" : [ {
    "id" : 0,
    "message" : "Test",
    "upvotes" : 1,
    "user" : "Anonymous"
  }, {
    "id" : 1,
    "message" : "Test2",
    "upvotes" : 1,
    "user" : "Anonymous"
  } ]
86
Big_Mac

Mise à jour: nous couvrons maintenant également cette question dans un épisode AskFirebase .

Le chargement de nombreux éléments à partir de Firebase ne doit pas nécessairement être lent, car vous pouvez canaliser les requêtes. Mais votre code rend cela impossible, ce qui conduira effectivement à des performances sous-optimales.

Dans votre code, vous demandez un élément au serveur, attendez qu'il soit renvoyé, puis chargez le suivant. Dans un diagramme de séquence simplifié qui ressemble à:

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 --

Dans ce scénario, vous attendez 30 fois votre temps aller-retour + 30 fois le temps nécessaire pour charger les données à partir du disque. Si (par souci de simplicité), nous disons que les allers-retours prennent 1 seconde et que le chargement d'un élément à partir du disque prend également une seconde à moins de 30 * (1 + 1) = 60 secondes.

Dans les applications Firebase, les performances seront bien meilleures si vous envoyez toutes les demandes (ou au moins un nombre raisonnable) en une fois:

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 --

Si nous supposons à nouveau un aller-retour d’une seconde et une seconde de chargement, vous attendez 30 * 1 + 1 = 31 secondes.

Donc: toutes les demandes passent par la même connexion. Étant donné cela, la seule différence entre get(1), get(2), get(3) et getAll([1,2,3]) est un surcoût pour les images.

J'ai mis en place un jsbin pour démontrer le comportement . Le modèle de données est très simple, mais il montre la différence.

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'))
  );
}

A titre de comparaison: le chargement séquentiel de 64 éléments prend 3,8 secondes sur mon système, tandis que leur chargement en pipeline (comme le fait le client Firebase de manière native) prend 600 ms. Les chiffres exacts dépendront de votre connexion (latence et bande passante), mais la version en pipeline devrait toujours être nettement plus rapide.

111
Frank van Puffelen