เพิ่มความเร็วในการดึงโพสต์สำหรับแอปโซเชียลเน็ตเวิร์กของฉันโดยใช้การสืบค้นแทนที่จะสังเกตเหตุการณ์เดียวซ้ำ ๆ


98

ฉันมีอาร์เรย์ของคีย์ที่นำไปสู่การโพสต์วัตถุสำหรับเครือข่ายโซเชียลของฉันเช่น / posts / id / (ข้อมูลโพสต์)

เมื่อฉันโหลดโพสต์ฉันโหลด / โพสต์ / 0 แล้ว / โพสต์ / 1 ฯลฯ โดยใช้observeSingleEventOfType(.Value)วิธีการ

ผมใช้การlazyTableViewโหลดครั้งละ 30 เครื่องและค่อนข้างช้า มีวิธีใดบ้างที่ฉันสามารถใช้หนึ่งในวิธีการสืบค้นหรือวิธีอื่นในการทำให้เร็วขึ้นแม้ว่าฉันจะต้องปรับโครงสร้างข้อมูลในโครงสร้าง JSON ก็ตาม

ฉันมาจาก Parse ที่นำแอปของฉันไปใช้ใหม่และจนถึงตอนนี้ประสบการณ์ก็ค่อนข้างดี เพียงสิ่งเดียวที่ฉันติดอยู่เล็กน้อย ขอบคุณล่วงหน้าสำหรับความช่วยเหลือ!

แก้ไข:

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

ฟังก์ชันวนซ้ำนี้จะเรียกใช้ค่าสำหรับหมายเลขคีย์ i จาก firebase เป็นหลัก หากเป็น NSNULL จะรู้ว่าเป็นโพสต์สุดท้ายที่สามารถโหลดได้และจะไม่ทำอีก หาก NSNULL ไม่ได้รับผลกระทบ แต่i % 29 == 0จะส่งกลับเป็นกรณีพื้นฐานดังนั้นจึงโหลดโพสต์ได้ครั้งละ 30 โพสต์เท่านั้น เมื่อผมตั้งdoneLoadingไปtrue, tableView.reloadData()จะเรียกว่าใช้สังเกตการณ์ทรัพย์สิน

นี่คือตัวอย่างของลักษณะของอาร์เรย์ที่ฉันเรียกดู

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

1
จะช่วยได้ง่ายกว่ามากหากคุณแสดงรหัสของคุณให้เราเห็นแทนที่จะอธิบาย รวม JSON ขั้นต่ำ (เป็นข้อความไม่ใช่ภาพหน้าจอ) และรหัสเพื่อสร้างปัญหาในคำถามของคุณอีกครั้งและเราจะดูว่าจะปรับปรุงได้อย่างไร อ่านข้อมูลเพิ่มเติมเกี่ยวกับMCVE
Frank van Puffelen

แก้ไขเพื่อรวมคำอธิบายรหัส
Big_Mac

คำตอบ:


126

อัปเดต: ตอนนี้เราครอบคลุมคำถามนี้ในตอน AskFirebaseด้วย

การโหลดหลายรายการจาก Firebase ไม่จำเป็นต้องช้าเพราะคุณสามารถส่งคำขอได้ แต่รหัสของคุณทำให้สิ่งนี้เป็นไปไม่ได้ซึ่งจะนำไปสู่ประสิทธิภาพที่ไม่ดีพอ

ในรหัสของคุณคุณขอรายการจากเซิร์ฟเวอร์รอให้รายการนั้นส่งคืนจากนั้นโหลดรายการถัดไป ในแผนภาพลำดับที่เรียบง่ายที่ดูเหมือน:

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

ในสถานการณ์นี้คุณกำลังรอ 30 เท่าของเวลาไปกลับ + 30 เท่าของเวลาที่ใช้ในการโหลดข้อมูลจากดิสก์ ถ้า (เพื่อความเรียบง่าย) เราบอกว่า roundtrips ใช้เวลา 1 วินาทีและการโหลดรายการจากดิสก์จะใช้เวลาหนึ่งวินาทีอย่างน้อยถึง 30 * (1 + 1) = 60 วินาที

ในแอปพลิเคชัน Firebase คุณจะได้รับประสิทธิภาพที่ดีขึ้นมากหากคุณส่งคำขอทั้งหมด (หรืออย่างน้อยก็จำนวนที่สมเหตุสมผล) ในคราวเดียว:

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

หากเราใช้เวลาไปกลับ 1 วินาทีและโหลด 1 วินาทีคุณจะรอ 30 * 1 + 1 = 31 วินาที

ดังนั้น: คำขอทั้งหมดต้องผ่านการเชื่อมต่อเดียวกัน ระบุว่าแตกต่างระหว่างget(1), get(2), get(3)และgetAll([1,2,3])เป็นค่าใช้จ่ายบางอย่างสำหรับเฟรม

ฉันจะตั้งค่าjsbin แสดงให้เห็นถึงพฤติกรรม แบบจำลองข้อมูลนั้นง่ายมาก แต่แสดงให้เห็นถึงความแตกต่าง

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

สำหรับการเปรียบเทียบ: การโหลด 64 รายการตามลำดับจะใช้เวลา 3.8 วินาทีในระบบของฉันในขณะที่การโหลดไปป์ไลน์ (เนื่องจากไคลเอนต์ Firebase ทำแบบเนทีฟ) จะใช้เวลา 600 มิลลิวินาที ตัวเลขที่แน่นอนจะขึ้นอยู่กับการเชื่อมต่อของคุณ (เวลาในการตอบสนองและแบนด์วิดท์) แต่เวอร์ชันแบบไพพ์ไลน์ควรเร็วกว่ามาก


12
ดีครับคุณปุ๊! นอกจากนี้การผูกมัดสัญญา (jQuery.whenAll (), q.all () หรือ Promise.all ()) ยังมีประโยชน์มากที่นี่หากคุณต้องการโหลดไอเท็มทั้งหมด แต่ยังคงต้องการคว้าไว้พร้อมกันก่อนที่จะดำเนินการบางอย่าง
Kato

5
เย็น. ไม่ได้คิดถึงเรื่องนั้นแม้ว่าฉันจะใช้มันไปแล้วก็ตาม :-)
Frank van Puffelen

2
@FrankvanPuffelen คุณคิดถูกแล้วจากมุมมองด้านประสิทธิภาพ แต่จะเกิดอะไรขึ้นถ้าหนึ่งในการโทรเหล่านี้ไม่กลับมาเนื่องจากข้อผิดพลาดประเภทใด ๆ คุณจะ 'ยกเลิก' คำขอที่เหลือที่รอดำเนินการได้อย่างไรหากใครก็ตามที่ทำไม่สำเร็จ ในกรณีของคำขอตามลำดับเราสามารถทราบได้ในรหัสว่าคำขอใดล้มเหลว กรุณาแบ่งปันความคิดของคุณ ขอบคุณ.
Perry

1
" The Promise.all () วิธีการ [... ] ปฏิเสธด้วยเหตุผลของสัญญาแรกที่ปฏิเสธ"
pejalo

4
เราจะทำ Promise.all ใน Android ได้อย่างไร? เราจะโหลดข้อมูลทั้งหมดใน android ได้อย่างไร
Muhammad chhota
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.