Mempercepat pengambilan posting untuk aplikasi jejaring sosial saya dengan menggunakan kueri alih-alih mengamati satu peristiwa berulang kali

98

Saya memiliki serangkaian kunci yang mengarah ke objek posting untuk jejaring sosial saya seperti so / posts / id / (post info)

Ketika saya memuat posting saya memuat / posts / 0 dan kemudian / posts / 1 dll menggunakan observeSingleEventOfType(.Value)metode.

Saya menggunakan lazyTableViewuntuk memuat 30 sekaligus dan itu cukup lambat. Apakah ada cara saya dapat menggunakan salah satu metode kueri atau cara lain untuk membuatnya lebih cepat bahkan jika saya harus merestrukturisasi data di pohon JSON saya.

Saya berasal dari Parse yang menerapkan ulang aplikasi saya dan sejauh ini pengalamannya cukup bagus. Hanya satu hal ini saya agak terjebak. Terima kasih sebelumnya atas bantuannya!

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

Fungsi rekursif ini pada dasarnya berjalan mendapatkan nilai untuk kunci nomor i dari firebase. Jika NSNULL ia tahu itu adalah posting terakhir yang mungkin dimuat dan tidak pernah melakukannya lagi. Jika NSNULL tidak terkena tetapi i % 29 == 0kemudian kembali sebagai kasus dasar sehingga hanya 30 posting yang dimuat pada satu waktu (0 diindeks). Saat saya menyetel doneLoadingke true, tableView.reloadData()dipanggil menggunakan pengamat properti.

Berikut adalah contoh dari array yang saya ambil

"ideaPosts" : [ {
    "id" : 0,
    "message" : "Test",
    "upvotes" : 1,
    "user" : "Anonymous"
  }, {
    "id" : 1,
    "message" : "Test2",
    "upvotes" : 1,
    "user" : "Anonymous"
  } ]
Big_Mac
sumber
1
Akan jauh lebih mudah membantu jika Anda menunjukkan kode Anda alih-alih mendeskripsikannya. Sertakan JSON minimum (sebagai teks, bukan tangkapan layar) dan kode untuk mereproduksi masalah dalam pertanyaan Anda dan kami dapat melihat bagaimana hal itu dapat ditingkatkan. Baca lebih lanjut tentang MCVE .
Frank van Puffelen
Diedit untuk menyertakan penjelasan kode
Big_Mac

Jawaban:

125

Pembaruan: kami sekarang juga membahas pertanyaan ini dalam episode AskFirebase .

Memuat banyak item dari Firebase tidak harus lambat, karena Anda dapat menyalurkan permintaan. Tetapi kode Anda membuat ini tidak mungkin, yang memang akan menyebabkan kinerja yang kurang optimal.

Dalam kode Anda, Anda meminta item dari server, tunggu item itu kembali dan kemudian muat yang berikutnya. Dalam diagram urutan yang disederhanakan yang terlihat seperti:

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

Dalam skenario ini Anda menunggu 30 kali waktu perjalanan pulang pergi + 30 kali waktu yang dibutuhkan untuk memuat data dari disk. Jika (demi kesederhanaan) kami mengatakan bahwa perjalanan bolak-balik membutuhkan waktu 1 detik dan memuat item dari disk juga membutuhkan satu detik yang paling sedikit hingga 30 * (1 + 1) = 60 detik.

Dalam aplikasi Firebase, Anda akan mendapatkan kinerja yang jauh lebih baik jika mengirim semua permintaan (atau setidaknya dalam jumlah yang wajar) sekaligus:

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

Jika kami mengasumsikan lagi perjalanan pulang pergi 1 detik dan pemuatan 1 detik, Anda menunggu selama 30 * 1 + 1 = 31 detik.

Jadi: semua permintaan melalui koneksi yang sama. Mengingat bahwa, satu-satunya perbedaan antara get(1), get(2), get(3)dan getAll([1,2,3])beberapa overhead untuk frame.

Saya menyiapkan jsbin untuk mendemonstrasikan perilakunya . Model datanya sangat sederhana, tetapi menunjukkan perbedaannya.

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

Sebagai perbandingan: memuat 64 item secara berurutan membutuhkan waktu 3,8 detik di sistem saya, sementara memuatnya melalui pipeline (seperti yang dilakukan klien Firebase secara asli) dibutuhkan 600ms. Jumlah pastinya akan bergantung pada koneksi Anda (latensi dan bandwidth), tetapi versi pipeline harus selalu lebih cepat secara signifikan.

Frank van Puffelen
sumber
12
Bagus, Puf! Selain itu, merangkai promise (jQuery.whenAll (), q.all (), atau Promise.all ()) bisa sangat berguna di sini jika Anda memerlukan semua item dimuat, tetapi masih ingin mengambilnya secara paralel, sebelum mengambil beberapa tindakan.
Kato
5
Keren. Bahkan tidak memikirkan itu, meskipun saya telah menggunakannya. :-)
Frank van Puffelen
2
@FrankvanPuffelen Anda benar dari sudut pandang kinerja, tetapi bagaimana jika salah satu panggilan ini tidak kembali karena semua jenis kesalahan? Bagaimana Anda bisa 'membatalkan' sisa permintaan yang tertunda jika ada yang gagal. Dalam kasus permintaan berurutan, kita dapat mengetahui dalam kode permintaan mana yang gagal. Silakan bagikan pemikiran Anda. Terima kasih.
Perry
1
" Metode Promise.all () [...] menolak dengan alasan janji pertama yang menolak."
pejalo
4
Bagaimana kita bisa melakukan Promise.all di android? Bagaimana kita bisa memuat semua data di android
Muhammad chhota