15 คะแนน โดย GN⁺ 2025-06-02 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • เช่นเดียวกับ Progressive JPEG สามารถส่งข้อมูล JSON ในสภาพที่ยังไม่สมบูรณ์ก่อน เพื่อให้ไคลเอนต์ค่อย ๆ นำเนื้อหาทั้งหมดไปใช้งานได้ทีละส่วน
  • วิธีพาร์ส JSON แบบเดิม มีปัญหาด้านประสิทธิภาพ เพราะไม่สามารถทำอะไรได้เลยจนกว่าจะรับข้อมูลครบทั้งหมด
  • ใช้วิธีแบบ Breadth-first แบ่งข้อมูลออกเป็นหลายชังก์ (ส่วนย่อย) โดยส่วนที่ยังไม่พร้อมจะแทนด้วย Promise และค่อย ๆ เติมเมื่อพร้อม ทำให้ไคลเอนต์ใช้งานข้อมูลที่ยังไม่สมบูรณ์ได้
  • แนวคิดนี้คือแกนสำคัญของ React Server Components(RSC) และใช้ <Suspense> เพื่อควบคุมสถานะการโหลดแบบเป็นขั้นตามที่ตั้งใจไว้
  • สามารถแยก data streaming ออกจาก flow การโหลด UI ที่ตั้งใจออกแบบไว้ เพื่อมอบประสบการณ์ผู้ใช้ที่ยืดหยุ่นยิ่งขึ้น

แนวคิดของ Progressive JPEG และ Progressive JSON

  • Progressive JPEG ไม่ได้โหลดภาพจากบนลงล่างทีเดียว แต่จะแสดงภาพรวมแบบเบลอก่อน แล้วค่อย ๆ ชัดขึ้น
  • ในทำนองเดียวกัน หากนำแนวทางแบบ progressive มาใช้กับการส่ง JSON ก็จะ ใช้งานข้อมูลบางส่วนได้ทันทีโดยไม่ต้องรอให้ทั้งหมดเสร็จสมบูรณ์
  • ในโครงสร้างข้อมูล JSON ตัวอย่าง วิธีปกติจะพาร์สได้ก็ต่อเมื่อรับข้อมูลครบจนถึงไบต์สุดท้ายเท่านั้น
  • ด้วยเหตุนี้ ไคลเอนต์จึงต้อง รอจนกว่าทุกอย่างจะถูกส่งมาครบ แม้กระทั่งส่วนที่ช้าของเซิร์ฟเวอร์ (เช่น การโหลด comments จาก DB ที่ช้า) ซึ่งเป็นมาตรฐานปัจจุบันที่ไม่มีประสิทธิภาพมาก

ข้อจำกัดของ streaming JSON parser

  • หากนำ streaming JSON parser มาใช้ ก็สามารถสร้าง ต้นไม้อ็อบเจ็กต์ข้อมูลที่ยังไม่สมบูรณ์ (ระหว่างทาง) ได้
  • แต่เมื่อฟิลด์ของแต่ละอ็อบเจ็กต์ (เช่น footer, รายการ comment หลายรายการ ฯลฯ) ถูกส่งมาเพียงบางส่วน จะเกิดปัญหา ชนิดข้อมูลไม่สอดคล้อง และยากต่อการรู้ว่าสมบูรณ์หรือยัง จึงนำไปใช้ได้ยาก
  • คล้ายกับการเรนเดอร์ HTML แบบสตรีมมิง หากประมวลผลสตรีมตามลำดับ ก็จะมีปัญหาเดียวกันคือ ส่วนที่ช้าเพียงจุดเดียวทำให้ผลลัพธ์ทั้งหมดล่าช้า
  • นี่จึงเป็นเหตุผลที่โดยทั่วไปไม่ค่อยมีการใช้งาน streaming JSON

ข้อเสนอเรื่องโครงสร้าง Progressive JSON

  • แทนที่จะใช้การสตรีมแบบ depth-first ตามเดิม (คือส่งโดยไล่ลึกลงไปในโครงสร้างต้นไม้ก่อน) จึงเสนอการใช้วิธี Breadth-first
  • ส่งเฉพาะอ็อบเจ็กต์ระดับบนสุดมาก่อน แล้วปล่อยค่าด้านล่างไว้เป็น placeholder คล้าย Promise ก่อน จากนั้นค่อยเติมแต่ละส่วนเป็นชังก์เมื่อพร้อม
  • ตัวอย่างเช่น ทุกครั้งที่เซิร์ฟเวอร์โหลดข้อมูลแบบอะซิงโครนัสเสร็จ ก็ส่งชังก์ที่เกี่ยวข้องมา และไคลเอนต์ก็ใช้งานได้เท่าที่พร้อมแล้ว
  • ทำให้เกิด การรับข้อมูลแบบอะซิงโครนัส (โหลดได้ตั้งแต่เนิ่น ๆ) และไม่ต้องรอทั้งระบบจนกว่าส่วนที่ช้าหลายส่วนจะประมวลผลเสร็จทั้งหมด
  • หาก ออกแบบไคลเอนต์ให้รองรับการรับชังก์แบบไม่เรียงลำดับและแบบเรียงลำดับบางส่วนได้ดี เซิร์ฟเวอร์ก็จะใช้กลยุทธ์การแบ่งชังก์ได้อย่างยืดหยุ่นมากขึ้น

Inlining และ Outlining: การส่งข้อมูลอย่างมีประสิทธิภาพ

  • ฟอร์แมตการสตรีม Progressive JSON ยังสามารถจัดการอ็อบเจ็กต์ที่ใช้ซ้ำ (เช่น การอ้างอิง userInfo เดียวกันจากหลายตำแหน่ง) ได้โดยไม่ต้องเก็บซ้ำ ด้วยการ แยกออกมาเป็นชังก์เดียวต่างหาก แล้วอ้างอิงร่วมกันจากแต่ละตำแหน่งได้
  • แยกเฉพาะส่วนที่ช้าออกมาเป็น placeholder แล้วส่งส่วนที่เหลือที่พร้อมก่อน เพื่อสร้าง data stream ที่มีประสิทธิภาพ
  • หากอ็อบเจ็กต์เดียวกันปรากฏหลายครั้ง ก็สามารถ ส่งเพียงครั้งเดียวแล้วนำกลับมาใช้ซ้ำ (Outlining) ได้
  • ด้วยวิธีนี้ แม้แต่ circular reference (โครงสร้างที่อ็อบเจ็กต์อ้างอิงตัวเอง) ก็ไม่เป็นปัญหาแบบ JSON ปกติ และสามารถ serialize ได้อย่างเป็นธรรมชาติผ่านโครงสร้างการอ้างอิงทางอ้อมระหว่างชังก์

การทำ progressive streaming ของ React Server Components(RSC)

  • React Server Components คือหนึ่งในตัวอย่างเด่นของการนำโมเดล progressive JSON streaming ไปใช้จริง
    • เซิร์ฟเวอร์ใช้โครงสร้างที่โหลดข้อมูลภายนอก (เช่น Post, Comments) แบบอะซิงโครนัส
    • ฝั่งไคลเอนต์จะ เก็บส่วนที่ยังมาไม่ถึงไว้เป็น Promise และค่อย ๆ เรนเดอร์ UI ตามลำดับที่ข้อมูลพร้อม
  • ใช้ React <Suspense> เพื่อกำหนดสถานะการโหลดตามที่ตั้งใจไว้
    • เพื่อ ป้องกันการกระโดดของหน้าจอที่ไม่จำเป็นในแง่ประสบการณ์ผู้ใช้ จึงไม่แสดงสถานะ Promise (ช่องโหว่) ทันที แต่ใช้ fallback ของ <Suspense> เพื่อสร้างลำดับการโหลดเป็นขั้น ๆ
    • แม้ข้อมูลจะมาถึงอย่างรวดเร็ว นักพัฒนาก็ยังควบคุมให้ UI ค่อย ๆ แสดงตามลำดับที่ออกแบบไว้ได้

สรุปและนัยสำคัญ

  • นวัตกรรมสำคัญของ React Server Components คือการ สตรีม props ของ component tree แบบค่อยเป็นค่อยไปจากด้านนอกเข้าไป
  • ดังนั้นจึงไม่จำเป็นต้องรอให้เซิร์ฟเวอร์เตรียมข้อมูลทุกอย่างเสร็จก่อน แต่สามารถแสดงส่วนสำคัญก่อนทีละน้อย พร้อมควบคุมสถานะรอโหลดได้อย่างละเอียด
  • ไม่ใช่แค่ตัวสตรีมมิงเท่านั้น แต่ยังต้องมีโครงสร้างสนับสนุนเชิงโมเดลการเขียนโปรแกรม (เช่น React <Suspense>) เพื่อใช้ประโยชน์จากมันด้วย
  • ด้วยแนวทางนี้ จึงช่วยบรรเทาคอขวดของวิธีส่งข้อมูลแบบเดิม เช่น ปัญหาที่ข้อมูลช้าเพียงส่วนเดียวทำให้ทั้งระบบล่าช้า

1 ความคิดเห็น

 
GN⁺ 2025-06-02
ความคิดเห็นจาก Hacker News
  • ดูเหมือนว่าบางคนจะตีความบทความนี้ตรงตัวเกินไป ขอย้ำว่า Dan Abramov ไม่ได้กำลังเสนอฟอร์แมตใหม่ชื่อ Progressive JSON
    • บทความนี้อธิบายแนวคิดของ React Server Components และกระบวนการแสดงต้นไม้คอมโพเนนต์ในรูปของอ็อบเจ็กต์ JavaScript แล้วส่งออกไปแบบสตรีม
    • วิธีนี้ทำให้สามารถใส่ “ช่องว่าง” ไว้ในต้นไม้คอมโพเนนต์ React ได้ โดยตอนแรกแสดงสถานะกำลังโหลดหรือ skeleton UI ไว้ก่อน แล้วค่อยเรนเดอร์ส่วนนั้นเต็มรูปแบบเมื่อได้รับข้อมูลจริงจากเซิร์ฟเวอร์
    • แบบนี้ช่วยให้แสดงสถานะกำลังโหลดได้ละเอียดขึ้นและทำให้หน้าจอแรกแสดงผลได้เร็วขึ้น
  • ในความเห็นของฉัน การที่ผู้คนจะต่อยอดแนวคิดนี้ไปใช้กับวิธีอื่นก็ถือว่าไม่เลว
    • เจตนาคืออยากอธิบายวิธี serialize ข้อมูลของ RSC ให้เป็นแพตเทิร์นที่ทั่วไปขึ้น ไม่ได้จำกัดอยู่แค่ React
    • อยากให้หลายไอเดียที่ค้นพบจาก React Server Components ซึมเข้าไปอยู่ในเทคโนโลยีหรือ ecosystem อื่น ๆ ด้วย
  • ฉันไม่ค่อยชอบแนวทาง progressive loading เท่าไร โดยเฉพาะประสบการณ์ที่คอนเทนต์ขยับไปมาเรื่อย ๆ
    • แพตเทิร์นที่แสดง UI ว่างเปล่าระหว่างโหลดนี่กวนใจเป็นพิเศษ
  • ตอนที่ยังใช้ Ember อยู่เมื่อไม่นานมานี้ก็มีแนวทางคล้ายกัน และจำได้ว่าการเขียน Ajax endpoint นั้นทรมานมาก
    • ดูเหมือนเจตนาจะเป็นการจัดวางโครงสร้างต้นไม้ใหม่ ให้ลูกบางตัวไปอยู่ท้ายไฟล์ เพื่อให้จัดการ DAG (กราฟไม่มีวงจร) ได้มีประสิทธิภาพ
    • ถ้าใช้ streaming parser แบบ SAX ก็สามารถเริ่ม paint ได้ก่อนตอนที่ข้อมูลยังมาไม่ครบ
    • แต่ถ้าออกแบบลำดับงานผิดใน VM แบบเธรดเดียว ปัญหากลับจะยิ่งบานปลาย
  • ตอนนี้ฉันใช้วิธี streaming partial JSON (Progressive JSON) จริงอยู่แล้วในการเชื่อมต่อกับเครื่องมือ AI
    • จากประสบการณ์ตรง วิธีนี้ไม่ได้มีประโยชน์แค่กับ RSC แต่ใช้ได้ในหลายที่ และมีคุณค่าทั้งฝั่งไคลเอนต์และเซิร์ฟเวอร์ในการทำงานจริง
  • ฉันตามดูทั้งงานพูด "2 computers" ของ Dan และโพสต์เกี่ยวกับ RSC ล่าสุด
    • Dan เป็นคนอธิบายเก่งที่สุดคนหนึ่งใน ecosystem ของ React แต่ถ้าเทคโนโลยีหนึ่งต้องอธิบายให้ซับซ้อนขนาดนี้ ก็อาจเป็นว่า
      1. มันเป็นเทคโนโลยีที่ไม่จำเป็นจริง ๆ หรือ
      2. มีปัญหาที่ abstraction
    • นักพัฒนาฝั่งฟรอนต์เอนด์ส่วนใหญ่ยังไม่เข้าใจแนวคิด RSC อย่างถ่องแท้
    • Vercel ทำให้ Next.js กลายเป็นเฟรมเวิร์ก React แบบดีฟอลต์ และการนำ RSC ไปใช้ก็แพร่ตามกระแสนี้
    • แม้แต่คนที่ใช้ Next.js เองก็ยังไม่เข้าใจขอบเขตของ Server Component ชัดเจน และมีการรับมาใช้แบบ “cargo cult” อยู่มาก
    • การที่ React ไม่รับ PR ที่เกี่ยวกับ Vite ก็ดูน่าสงสัย เหมือนแรงผลัก RSC อาจไม่ได้มีไว้เพื่อผู้ใช้หรือนักพัฒนาเท่าไร แต่เป็นกลยุทธ์ขายแพลตฟอร์มโฮสติ้งของบริษัทแพลตฟอร์มมากกว่า
    • ย้อนกลับไปดูแล้ว การที่ Vercel ดึงทีมดั้งเดิมของ React เข้าไปจำนวนมากก็ดูเหมือนตั้งใจจะกำหนดอนาคตของ React
    • มีการทักท้วงว่าการตีความแรงจูงใจหรือภูมิหลังทางประวัติศาสตร์นั้นอาจผิด พร้อมอธิบายสถานะปัจจุบันของการรองรับ Vite
    • มีการบอกว่าการรวมเข้ากับ Vite ตอนนี้ทีม Vite กำลังปรับปรุงอยู่ เพราะมีข้อจำกัดทางเทคนิคที่ DEV environment ยังต้องทำ bundling
    • มีความเห็นว่าข้ออ้างที่ว่าคนไม่เข้าใจ RSC เป็นตรรกะแบบวนลูปในตัวเอง
    • จะไม่ชอบ RSC ก็ได้ แต่ข้างในนั้นก็ยังมีไอเดียที่น่าสนใจพอจะหยิบไปใช้กับเทคโนโลยีอื่นได้
    • มากกว่าจะโน้มน้าวใคร ก็หวังให้แต่ละคนหยิบส่วนที่น่าสนใจและมีประโยชน์ไปใช้กันเอง
  • แน่นอนว่ายังสามารถทำ SPA ให้เป็น static site แล้วเอาขึ้น CDN ได้ และ Next.js ก็ self-host แบบโหมด “dynamic” ได้เช่นกัน
    • เพียงแต่ในความเป็นจริง การทำฟีเจอร์ serverless rendering ทั้งชุดของ Next.js ให้สมบูรณ์บนที่อื่นที่ไม่ใช่ Vercel นั้นทำได้ยาก เพราะมี “magic” ที่ไม่ได้มีเอกสารชัดเจน
    • ประเด็นนี้เองก็มีข้อเสนออย่างเป็นทางการให้ใช้ adapter เพื่อให้มี API ที่สม่ำเสมอบนหลายแพลตฟอร์ม: https://github.com/vercel/next.js/discussions/77740
    • ฉันมองว่าแรงผลัก RSC น่าจะไม่ได้มาจากผลประโยชน์ของบริษัทเท่านั้น แต่เกิดจากการตระหนักว่ารูปแบบการสร้างเว็บแบบเดิม ๆ (SSR + progressive enhancement ฝั่งไคลเอนต์เล็กน้อย) มีข้อดีจริงมาก
    • แม้แค่ SSR เองก็ยังมีปัญหาที่ business logic ถูกย้ายไปอยู่ฝั่งไคลเอนต์มากเกินจำเป็น
  • ตัว RSC เองเป็นเทคโนโลยีที่น่าสนใจ แต่ในงานจริงฉันคิดว่ามันไม่ค่อยสมเหตุสมผลนัก
    • มีภาระต้องดูแลเซิร์ฟเวอร์ backend แบบ Node/Bun จำนวนมากเพื่อเรนเดอร์คอมโพเนนต์ที่ซับซ้อน
    • สู้ใช้หน้า static หรือ React SPA + Go API server จะมีประสิทธิภาพกว่ามาก
    • ผลลัพธ์ใกล้เคียงกันได้ด้วยทรัพยากรที่น้อยกว่ามาก
  • การอธิบายเทคโนโลยีใหม่ได้ซับซ้อนไม่ได้แปลว่ามันไม่จำเป็นหรือเป็น abstraction ที่ผิดเสมอไป และก็มีปัญหาบางอย่างที่คุ้มจะยอมรับความซับซ้อนนั้น
    • รอดูต่อไปว่าเทคโนโลยีนี้จะพัฒนาไปอย่างไร
  • มีความคิดว่าสามารถใช้โครงสร้างโค้ดของ RSC มาสร้างหน้า static ที่แยก HTML/CSS/JS ออกเป็นชิ้นเล็ก ๆ ได้
    • ในบทความมีการเสนอ placeholder ‘$1’ ซึ่งถ้าแทนเป็น URI ก็อาจไม่ต้องมีเซิร์ฟเวอร์เลยก็ได้ (เพราะส่วนใหญ่ไม่ได้จำเป็นต้องใช้ dynamic SSR)
    • ข้อเสียคือวิธีนี้ ความเร็วของ pipeline การอัปเดตจะสำคัญมากเวลาคอนเทนต์เปลี่ยน โดยเฉพาะการ deploy แบบสตรีมของ static site ที่คอมไพล์แล้วไปยัง S3
    • ยกตัวอย่างเช่นเว็บหนังสือพิมพ์ที่ prerender บทความไว้จำนวนมาก เมื่อต้องเปลี่ยนแค่บางส่วนก็จำเป็นต้องมีการจัดการ content diff อย่างชาญฉลาด เช่น rebuild เฉพาะส่วนนั้นอย่างมีประสิทธิภาพ
  • ในงานจริง พอเจอการอ้างเรื่อง performance optimization ที่ไปโหลดข้อมูลหลาย MB มาประมวลผลตรรกะซับซ้อนในฟรอนต์เอนด์ระดับมิลลิวินาที ก็ทำให้ตระหนักว่าจริง ๆ แล้วการปรับ BFF หรือสถาปัตยกรรม รวมถึงการสร้าง API ที่ lean กว่านั้น เป็นทางแก้ที่มีประสิทธิผลกว่ามาก
    • เคยมีความพยายามผ่าน GraphQL, http2 ฯลฯ แต่สุดท้ายก็ไม่ใช่การแก้ปัญหาที่แก่นจริง ๆ และตราบใดที่มาตรฐานเว็บไม่พัฒนา ก็อาจยังไม่เกิดการเปลี่ยนกระบวนทัศน์
    • เฟรมเวิร์กใหม่ ๆ เองก็ยังติดข้อจำกัดนี้เหมือนกัน
  • มีคำอธิบายว่า RSC โดยเนื้อแท้แล้วคือบทบาทแบบ BFF (Backend for Frontend) ตามที่อธิบายไว้ท้ายบทความ
    • เป็นโครงสร้างที่ทำให้ตรรกะ API กลายเป็นคอมโพเนนต์
    • ดูบทความยาวของฉันได้ที่: https://overreacted.io/jsx-over-the-wire/ (เรื่อง BFF อยู่ช่วงกลางของส่วนแรก)
  • มีความเห็นว่าความหมายของ “ลดเวลาโหลดหน้าเป็น ms” นั้นขึ้นอยู่กับว่าหมายถึงอะไร
    • ถ้าต้องการ optimize ค่า Time to first render หรือ time to visually complete การส่ง skeleton UI ว่าง ๆ ไปก่อนแล้วค่อยรับข้อมูลจาก API เพื่อ hydrate จะให้ความรู้สึกว่าเร็วที่สุด
    • แต่ถ้าต้องการให้ time to first input หรือ time to interactive เร็ว ก็ควรเรนเดอร์ข้อมูลผู้ใช้ได้ทันที ซึ่งในกรณีนี้ backend ได้เปรียบกว่ามากเพราะลด network call ได้
    • ส่วนใหญ่ผู้ใช้มักชอบแบบหลัง และสำหรับแอป CRUD SaaS ก็มักเหมาะกับ server-side rendering ขณะที่แอปที่งานออกแบบสำคัญอย่าง Figma เหมาะกับการใช้ข้อมูล static บนไคลเอนต์แล้วค่อย fetch ข้อมูลเพิ่ม
    • ไม่มี “ทางออกเดียวที่ใช้ได้กับทุกปัญหา” และจุดที่ควร optimize ก็เป็นเรื่องของการเลือกตามบริบท
    • ยังมีอีกหลายปัจจัย เช่น ประสบการณ์การพัฒนา โครงสร้างทีม ฯลฯ ที่ส่งผลต่อการเลือกเทคโนโลยี
  • ขอบคุณที่ทำให้ฉันเข้าใจเสียทีว่าทำไมเวลาโหลด Facebook แล้วคอนเทนต์หลักถึงมักเรนเดอร์เป็นอย่างสุดท้าย
  • มีคนถามว่า BFF ที่พูดถึงตรงนี้คืออะไร
  • มีปฏิกิริยาว่าตัวย่อเยอะเกินไป เลยอยากรู้ว่า FE กับ BFF คืออะไร
  • ฉันไม่ค่อยอยากใช้ไอเดีย Progressive JSON ตรง ๆ และคิดว่ามีทางเลือกหลายแบบ
    • วิธีที่ง่ายที่สุดคือแบ่ง JSON object ขนาดใหญ่อันเดียวออกเป็นหลายส่วน แล้วส่งแบบ ‘JSON lines’
    • ส่งข้อมูล header แค่ครั้งเดียว แล้วส่ง array ขนาดใหญ่ทีละบรรทัดเพื่อให้ประมวลผลแบบสตรีมได้มีประสิทธิภาพขึ้น
    • ถ้าอ็อบเจ็กต์ใหญ่กว่านี้ก็อาจใช้วิธีเดียวกันแบบ recursive ได้ แต่ก็อาจซับซ้อนเกินไป
    • เซิร์ฟเวอร์ยังอาจรับประกันลำดับของ property อย่างชัดเจน เพื่อให้ progressive parsing และการแยกส่วนทำได้
    • ท้ายที่สุดแล้ววิธีนี้อาจไม่เหมาะกับโครงสร้างที่ใหญ่มากจริง ๆ แต่สำหรับสถานการณ์ JSON ขนาดใหญ่ที่พบบ่อย ๆ ก็เป็นเครื่องมือที่ใช้งานได้จริงพอสมควร
  • โดยไม่ต้องทำเครื่องหมายช่องว่าง (holes) ไว้อย่างชัดเจน ก็สามารถส่งข้อความสตรีมตามลำดับและส่งเฉพาะ delta (diff) ได้
    • ถ้าใช้ฟอร์แมต delta ชื่อ ‘Mendoza’ ก็ส่ง patch (diffs) ที่กะทัดรัดมากได้ทั้งใน Go และ JS/Typescript: https://github.com/sanity-io/mendoza, https://github.com/sanity-io/mendoza-js
    • ไม่ว่าจะเป็น binary diff ของ zstd หรือแบบ Mendoza ก็สามารถเก็บข้อมูล serialized ไว้ในหน่วยความจำเพียงบางส่วนเพื่อทำ patch ได้อย่างมีประสิทธิภาพ
    • React เองก็จำเป็นต้องมีวิธีเทียบความต่างหรือใส่เฉพาะสิ่งที่เปลี่ยนไปอยู่แล้ว จึงเป็นแนวทางที่มีความหมาย
  • ในการสตรีมข้อมูล UI นั้น แค่อาร์เรย์ว่างหรือ null ยังไม่พอ และจำเป็นต้องมีข้อมูลแยกต่างหากว่าตอนนี้ข้อมูลส่วนไหนยังมาไม่ถึง (pending)
    • GraphQL streaming payload เลือกแนวทางแบบผสม คือมีทั้งสคีมาข้อมูลที่ถูกต้อง ข้อมูลสถานะที่ยังมาไม่ถึง และการทำ patch ภายหลัง
  • ต้องรู้ว่าตรงไหนคือ “ช่องว่าง” จึงจะแสดงสถานะกำลังโหลดได้ง่าย
  • ถ้าต้องการ progressively decode JSON ฝั่งไคลเอนต์ มีการแนะนำไลบรารีชื่อ jsonriver: https://github.com/rictic/jsonriver
    • API เรียบง่ายมาก ประสิทธิภาพก็ดีและมีการทดสอบเพียงพอ
    • มันจะ parse ชิ้นส่วนสตริงที่สตรีมเข้ามาให้กลายเป็นค่าที่สมบูรณ์ขึ้นเรื่อย ๆ
    • รับประกันว่าผลลัพธ์สุดท้ายจะเหมือนกับ JSON.parse
  • มีความเห็นว่านี่เป็นวิธีที่น่าสนุกและใช้ได้กับโครงสร้างแบบต้นไม้ทุกประเภท
    • ถ้าเป็นข้อมูลแบบต้นไม้ จะสามารถแทนด้วยเวกเตอร์ parent, type, data และ string table ได้ ทำให้ส่วนที่เหลือลดเหลือเพียงจำนวนเต็มไม่กี่ตัว
    • ส่ง string table กับ type info เป็น header ล่วงหน้า แล้วค่อยสตรีม parent และ data vector chunk ทีละโหนด
    • จะสตรีมแบบ depth-first หรือ breadth-first ก็แค่เปลี่ยนลำดับของ chunk เท่านั้น
    • น่าจะช่วยปรับปรุง UX เวลาโหลดในแอปที่ทำงานผ่านเครือข่ายได้มาก
    • สามารถส่ง table และ node chunk สลับกันไป พร้อมแสดงผลต้นไม้บนเว็บในลำดับใดก็ได้
    • ถ้ามี preorder traversal กับข้อมูล depth ก็สามารถกู้โครงสร้างต้นไม้กลับมาได้แม้ไม่มี node id
    • เอาไอเดียนี้ไปทำเป็นไลบรารีเล็ก ๆ ก็ดูน่าลอง
  • มีข้อโต้แย้งว่าแอปส่วนใหญ่ไม่จำเป็นต้องมีระบบโหลดที่ “ประณีต” แบบนี้ และส่วนใหญ่มักแทนได้ด้วยการเรียก API หลายครั้งแบบง่าย ๆ
    • มีคำชี้แจงว่าตั้งใจเพียงอธิบายวิธีทำงานของ wire protocol ของ RSC ไม่ได้มีเจตนาแนะนำให้ใครลงมือทำแบบนี้เอง
    • การเข้าใจหลักการของเครื่องมือต่าง ๆ ก็ช่วยให้ยืมไอเดียหรือ remix ไปใช้ในหลายบริบทได้
    • แม้จะคิดว่ากลยุทธ์เรียกหลายครั้งมีปัญหา n*n+1 แต่ก็สามารถส่งข้อมูลแบบแบนแทนการซ้อนอ็อบเจ็กต์สไตล์ OOP/ORM ได้ เช่นในกรณีคอมเมนต์
    • หากเป็นแบบนี้ การทำ endpoint ที่มี type ชัดเจนด้วย protobuf เป็นต้น ก็มีข้อดีเหมือนกัน
    • ถ้าแยก comments ออก ก็ใช้แค่ 2 ครั้งก็พอ (หน้า+โพสต์ และคอมเมนต์แยก) ซึ่งยังช่วยเรื่อง pre-render optimization ได้
    • หากมีเครื่องมือที่ดีและกำหนดตัวเลือกไว้ล่วงหน้าแล้ว ก็อาจไม่จำเป็นต้องทำ customization เชิงลึกโดยเพิ่มความซับซ้อนของ implementation มากเกินไป
    • ควรตระหนักว่าฟีเจอร์ที่ซับซ้อนเกินความจำเป็นอาจกลายเป็นโทษต่อทั้งผู้ใช้และนักพัฒนาได้
    • เหมือนคำพูดว่า 640K ก็พอแล้ว ฉันกลับคิดว่า progressive/partial reads น่าจะมีบทบาทจริงมากต่อความเร็ว UX ในยุค WASM
    • ถ้าวิธีเข้ารหัสแบบไบนารีอย่าง protobuf มี partial read และ well-defined streaming เพิ่มเข้ามา ภาระของวิศวกรอาจมากขึ้น แต่ UX ที่ได้ก็น่าจะดีขึ้นมาก
  • มีความเห็นว่า Progressive JPEG จำเป็นเพราะธรรมชาติของไฟล์มีเดีย แต่กับ Text/HTML แล้วไม่จำเป็น และกลายเป็นความย้อนแย้งที่เพิ่มความซับซ้อนเพราะ JS bundle ใหญ่เกินไป
    • มีการชี้ว่าต้นเหตุของความช้าในโลกจริงไม่ได้มีแค่เรื่อง “ขนาด” ของข้อมูลเท่านั้น
    • บางครั้ง query ข้อมูลฝั่งเซิร์ฟเวอร์เองก็กินเวลานาน หรือเครือข่ายอาจช้า ซึ่งในกรณีนี้ progressive reveal ก็ยังมีความหมาย
    • แทนที่จะรอให้ข้อมูลครบทั้งหมด การเลือกเรนเดอร์เป็นขั้น ๆ พร้อมแสดง loading UI ในเวลาที่เหมาะสม อาจให้ประโยชน์ต่อประสบการณ์ผู้ใช้จริงมากกว่า
  • มีความคิดว่ากลยุทธ์แยก endpoint นั้นเป็นทางออกที่มีข้อดีอยู่แล้วหลายอย่าง (เช่น เลี่ยง Head of line blocking, เพิ่มตัวเลือกการกรอง, รองรับ live update, ปรับปรุงประสิทธิภาพแบบอิสระ ฯลฯ)
    • มีมุมมองว่าความพยายามจะปฏิบัติต่อแอปพลิเคชันเหมือนเป็น document platform นั้นคือปัญหาที่แท้จริง
    • แอปพลิเคชันจริงไม่ได้ทำงานเหมือน “เอกสาร” และเพื่อปิดช่องว่างนี้จึงต้องมีโค้ดและโครงสร้างพื้นฐานเสริมอีกมาก
    • มีบทความยาวสองชิ้นที่อธิบายต่อถึงข้อเสียจริงและทิศทางวิวัฒนาการของการใช้ endpoint แยก: https://overreacted.io/one-roundtrip-per-navigation/, https://overreacted.io/jsx-over-the-wire/
    • สรุปคือ endpoint จะกลายเป็นสัญญา API แบบ “ทางการ” ระหว่างเซิร์ฟเวอร์กับไคลเอนต์ในที่สุด และเมื่อโค้ดถูกแยกเป็นโมดูลมากขึ้น ก็อาจเสียประสิทธิภาพได้ (เช่น เกิด waterfall)
    • การรวมการตัดสินใจต่าง ๆ ไปจัดการฝั่งเซิร์ฟเวอร์ในครั้งเดียว (coalescing) อาจเป็นทางเลือกที่ดีกว่าทั้งในแง่ประสิทธิภาพและความยืดหยุ่นของโครงสร้าง