Tek bir etkinliği tekrar tekrar gözlemlemek yerine sorgu kullanarak sosyal ağ uygulamam için gönderileri getirmeyi hızlandır


98

So / posts / id / (gönderi bilgisi) gibi sosyal ağım için nesneler göndermeye yol açan bir dizi anahtarım var

Gönderileri yüklediğimde observeSingleEventOfType(.Value)yöntemi kullanarak / posts / 0 ve ardından / posts / 1 etc yüklerim.

Bir kullanmak lazyTableViewbir anda yük 30'a ve oldukça yavaştır. JSON ağacımdaki verileri yeniden yapılandırmam gerekse bile sorgu yöntemlerinden birini veya daha hızlı hale getirmenin başka bir yolunu kullanabilmemin bir yolu var mı?

Parse'den uygulamamı yeniden uygulayarak geliyorum ve şu ana kadar elde ettiğim deneyim oldukça iyi. Sadece bu biraz takılıp kaldığım tek şey. Yardım için şimdiden teşekkürler!

DÜZENLE:

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

Bu özyinelemeli işlev, esas olarak, firebase'den anahtar numarası i'nin değerini alarak çalışır. Eğer NSNULL ise, yüklenebilecek en son gönderi olduğunu bilir ve bir daha asla yapmaz. NSNULL isabet almazsa ancak i % 29 == 0temel durum olarak geri döner, böylece bir seferde yalnızca 30 gönderi yüklenir (0 indekslenir). Ben ayarlandığında doneLoadingiçin true, tableView.reloadData()bir özellik gözlemci kullanılarak adlandırılır.

İşte getirdiğim dizinin nasıl göründüğüne dair bir örnek

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

1
Kodunuzu açıklamak yerine bize gösterirseniz yardımcı olmanız çok daha kolay olacaktır. Sorunuzdaki sorunu yeniden oluşturmak için minimum JSON (metin olarak, ekran görüntüsü değil) ve kodu ekleyin ve nasıl geliştirilebileceğini görebiliriz. Bir MCVE hakkında daha fazla bilgi edinin .
Frank van Puffelen

Kod açıklamasını içerecek şekilde düzenlendi
Big_Mac

Yanıtlar:


125

Güncelleme: Şimdi bu soruyu AskFirebase bölümünde de ele alıyoruz .

Firebase'den birçok öğe yüklemenin yavaş olması gerekmez, çünkü istekleri ardışık düzenleyebilirsiniz. Ancak kodunuz bunu imkansız hale getiriyor ve bu da gerçekten de optimal performansın sağlanmasına yol açacaktır.

Kodunuzda, sunucudan bir öğe talep edersiniz, bu öğenin geri dönmesini bekleyin ve ardından bir sonrakini yükleyin. Basitleştirilmiş bir dizi diyagramında şuna benzer:

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

Bu senaryoda, gidiş dönüş sürenizin 30 katı + verileri diskten yüklemek için gereken sürenin 30 katı bekliyorsunuz. Eğer (basitlik adına) gidiş-dönüşlerin 1 saniye sürdüğünü ve diskten bir öğenin yüklenmesinin de 30 * (1 + 1) = 60 saniyeden en az bir saniye sürdüğünü söyleriz.

Firebase uygulamalarında, tüm istekleri (veya en azından makul sayılarını) tek seferde gönderirseniz çok daha iyi performans elde edersiniz:

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

Yine 1 saniyelik bir gidiş dönüş ve 1 saniyelik yükleme varsayarsak, 30 * 1 + 1 = 31 saniye bekliyorsunuz.

Yani: tüm istekler aynı bağlantıdan geçer. Arasındaki tek fark göz önüne alındığında get(1), get(2), get(3)ve getAll([1,2,3])çerçeveler için bazı havai olduğunu.

Davranışı göstermek için bir jsbin kurdum . Veri modeli çok basit, ancak farkı gösteriyor.

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

Karşılaştırma için: 64 öğeyi ardışık olarak yüklemek, sistemimde 3,8 saniye sürerken, bunları ardışık düzende yüklerken (Firebase istemcisinin yerel olarak yaptığı gibi) 600 ms sürer. Kesin sayılar bağlantınıza (gecikme ve bant genişliği) bağlı olacaktır, ancak ardışık düzen sürümünün her zaman önemli ölçüde daha hızlı olması gerekir.


12
Güzel, Puf! Ayrıca, zincirleme vaatleri (jQuery.whenAll (), q.all () veya Promise.all ()), tüm öğelerin yüklenmesine ihtiyacınız varsa, ancak yine de bir işlem yapmadan önce bunları paralel olarak almak istiyorsanız burada çok kullanışlı olabilir.
Kato

5
Güzel. Kullanıyor olmama rağmen bunu düşünmedim bile. :-)
Frank van Puffelen

2
@FrankvanPuffelen Performans açısından haklısınız ama ya bu aramalardan biri herhangi bir hata nedeniyle geri dönmediyse? Bunlardan herhangi biri başarısız olursa, bekleyen isteklerin geri kalanını nasıl 'iptal edebilirsiniz'? Sıralı istekler durumunda, hangi isteğin başarısız olduğunu kodla öğrenebiliriz. Lütfen düşüncelerinizi paylaşın. Teşekkürler.
Perry

1
" Promise.all () yöntemi [...], reddeden ilk sözün nedeni ile reddeder."
pejalo

4
Promise.all'ı android'de nasıl yapabiliriz? Android'de tüm verileri nasıl yükleyebiliriz
Muhammad chhota
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.