2016-03-11 1 views
54

Ich habe eine Reihe von Schlüsseln, die dazu führen, Objekte für mein soziales Netzwerk wie posts/id/(Post-Info)Beschleunigen Holen von Posts für meine Social-Network-App mit Abfrage anstelle eines einzelnen Ereignisses wiederholt zu beobachten

Wenn ich die Posts lade, lade ich/posts/0 und dann/posts/1 usw. mit der Methode observeSingleEventOfType (.Value).

Ich benutze eine LazyTableView, um 30 auf einmal zu laden, und es ist ziemlich langsam. Gibt es eine Möglichkeit, eine der Abfrage-Methoden oder eine andere Möglichkeit, um es schneller zu machen, auch wenn ich die Daten in meinem JSON-Baum neu strukturieren muss.

Ich komme aus Parse meine App re-implementieren und so weit die Erfahrung als recht gut gewesen. Nur diese eine Sache bin ich ein bisschen fest. Vielen Dank im Voraus für die Hilfe!

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

Diese rekursive Funktion im Wesentlichen läuft der Wert für die Schlüsselnummer bekommen i von Feuerbasis. Wenn es NSNULL ist, weiß es, dass es der letzte mögliche Post ist, der geladen wird, und nie wieder tut. Wenn NSNULL nicht getroffen wird, aber i% 29 == 0, wird als Basisfall zurückgegeben, so dass nur 30 Posts gleichzeitig geladen werden (0 indiziert). Wenn ich doneLoading auf true setze, wird tableView.reloadData() mit einem Property Observer aufgerufen. Hier

ist ein Beispiel, was das Array Ich bin Aussehen holen wie

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

Es wird viel einfacher zu helfen, wenn Sie uns Ihren Code zeigen, anstatt ihn zu beschreiben. Fügen Sie den minimalen JSON (als Text, kein Screenshot) und den Code ein, um das Problem in Ihrer Frage zu reproduzieren und wir können sehen, wie es verbessert werden kann. Lesen Sie mehr über [MCVE] (http://stackoverflow.com/help/mcve). –

+0

Bearbeitet, um Codeerklärung zu enthalten –

Antwort

78

Update: wir nun auch diese Frage decken in einem AskFirebase episode.

Das Laden vieler Elemente aus Firebase muss nicht langsam sein, da Sie die Anfragen weiterleiten können. Aber Ihr Code macht dies unmöglich, was tatsächlich zu einer suboptimalen Leistung führt.

In Ihrem Code fordern Sie einen Artikel vom Server an, warten Sie, bis dieser Artikel zurückgegeben wurde, und laden Sie dann den nächsten Artikel. In einem vereinfachten Ablaufdiagramm, das wie folgt aussieht: 30 mal Ihre Umlaufzeit + 30-mal die Zeit, die Sie warten

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

In diesem Szenario, um die Daten von der Festplatte zu laden. Wenn wir (aus Gründen der Einfachheit) sagen, dass Roundtrips 1 Sekunde dauern und das Laden eines Gegenstands von der Platte auch eine Sekunde dauert, beträgt diese mindestens 30 * (1 + 1) = 60 Sekunden.

In Firebase Anwendungen Sie werden viel bessere Leistung, wenn man alle Anfragen senden (oder zumindest eine angemessene Anzahl von ihnen) in einem Rutsch:

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

Wenn wir wieder eine 1 Sekunde Rundfahrt übernehmen und Nach 1 Sekunde Ladezeit warten Sie auf 30 * 1 + 1 = 31 Sekunden.

Also: alle Anfragen durchlaufen die gleiche Verbindung. Da der einzige Unterschied zwischen get(1), get(2), get(3) und getAll([1,2,3]) ist einige Overhead für die Frames.

Ich habe eine jsbin to demonstrate the behavior eingerichtet. Das Datenmodell ist sehr einfach, aber es zeigt den Unterschied.

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

Zum Vergleich: sequentieller Laden 64 Artikel dauern 3,8 Sekunden auf meinem System, während sie überlappt Laden (wie die Firebase Client nativ tut) dauert es 600 ms. Die genauen Zahlen hängen von Ihrer Verbindung (Latenz und Bandbreite) ab, aber die Pipeline-Version sollte immer deutlich schneller sein.

+10

Schön, Puf! Auch Verkettungsversprechungen (jQuery.whenAll(), q.all() oder Promise.all()) können hier sehr nützlich sein, wenn Sie alle geladenen Elemente benötigen, sie aber dennoch parallel abrufen möchten, bevor Sie etwas unternehmen. – Kato

+4

Kühl. Daran habe ich nicht einmal gedacht, obwohl ich es benutzt habe. :-) –

+0

Fehle ich etwas? Sie rufen zu loadVideosSequential nur auf, nachdem das vorherige "einmal" den Snapshot abgerufen hat, ähnlich wie @ Big_Mac_24, aber mit anderem API-Aufruf. Können Sie den Unterschied bitte erklären? – Shirane85

Verwandte Themen