2016-03-11 3 views
54

Ho una serie di chiavi che portano a postare oggetti per il mio social network come/posts/id/(informazioni post)Accelerare il recupero di post per la mia app di social network utilizzando la query anziché osservare ripetutamente un singolo evento

Quando carico i post, carico/posts/0 e quindi/posts/1 ecc. Usando il metodo observSingleEventOfType (.Value).

Io uso un lazyTableView per caricare 30 alla volta ed è piuttosto lento. C'è un modo per utilizzare uno dei metodi di query o un altro modo per renderlo più veloce anche se devo ristrutturare i dati nel mio albero JSON.

Sto venendo da Parse ri-implementando la mia app e finora l'esperienza è stata abbastanza buona. Solo questa cosa sono un po 'bloccata. Grazie in anticipo per l'aiuto!

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

Questa funzione ricorsiva gestisce essenzialmente ottenere il valore per i numero del tasto da Firebase. Se è NSNULL, sa che è l'ultimo post possibile da caricare e non lo fa mai più. Se NSNULL non viene colpito ma i% 29 == 0, restituisce come caso base quindi vengono caricati solo 30 post alla volta (0 indicizzati). Quando ho impostato doneLoading su true tableView.reloadData() viene chiamato utilizzando un osservatore delle proprietà.

Ecco un esempio di ciò che la serie che sto recupero assomiglia

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

Sarà molto più facile aiutare se ci mostri il tuo codice invece di descriverlo. Includere il minimo JSON (come testo, non uno screenshot) e il codice per riprodurre il problema nella tua domanda e possiamo vedere come può essere migliorato. Maggiori informazioni su un [MCVE] (http://stackoverflow.com/help/mcve). –

+0

Modificato per includere la spiegazione del codice –

risposta

78

Aggiornamento: noi ora copriamo anche questa domanda in un AskFirebase episode.

Il caricamento di molti elementi da Firebase non deve essere lento, poiché è possibile eseguire la pipeline delle richieste. Ma il tuo codice lo sta rendendo impossibile, il che infatti porterà a prestazioni non ottimali.

Nel codice, si richiede un elemento dal server, attendere che quell'elemento torni e quindi caricare quello successivo. In un diagramma di sequenza semplificato che assomiglia:

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 questo scenario si sta aspettando per 30 volte il tempo di andata e ritorno + 30 volte il tempo necessario per caricare i dati dal disco. Se (per ragioni di semplicità) diciamo che i viaggi di andata e ritorno impiegano 1 secondo e il caricamento di un oggetto dal disco richiede anche un secondo che almeno a 30 * (1 + 1) = 60 secondi.

Nelle applicazioni Firebase si otterrà prestazioni molto migliori se si invia tutte le richieste (o almeno un numero ragionevole di essi) in una sola volta:

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

Se abbiamo di nuovo ipotizza un 1 secondo andata e ritorno e 1 secondo di caricamento, stai aspettando 30 * 1 + 1 = 31 secondi.

Quindi: tutte le richieste passano attraverso la stessa connessione. Dato che, l'unica differenza tra get(1), get(2), get(3) e getAll([1,2,3]) è un overhead per i frame.

Ho impostato un jsbin to demonstrate the behavior. Il modello dati è molto semplice, ma mostra la differenza.

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

Per fare un confronto: in sequenza di caricamento 64 articoli dura 3,8 secondi sul mio sistema, durante il caricamento di loro pipeline (come il client Firebase lo fa in modo nativo) ci vuole 600ms. I numeri esatti dipenderanno dalla tua connessione (latenza e larghezza di banda), ma la versione pipeline dovrebbe essere sempre significativamente più veloce.

+10

Nice, Puf! Inoltre, concatenare promesse (jQuery.whenAll(), q.all() o Promise.all()) può essere molto utile qui se hai bisogno di tutti gli elementi caricati, ma vuoi comunque catturarli in parallelo, prima di prendere qualche azione. – Kato

+4

Fresco. Non ci ho nemmeno pensato, anche se l'ho usato. :-) –

+0

Mi manca qualcosa? Stai chiamando to loadVideosSequential solo dopo che il precedente "una volta" ha recuperato l'istantanea, simile a come @ Big_Mac_24 fa ma con una chiamata API diversa. Puoi spiegare la differenza, per favore? – Shirane85

Problemi correlati