- Giống như JPEG lũy tiến, dữ liệu JSON cũng có thể được gửi trước trong trạng thái chưa hoàn chỉnh để client dần dần tận dụng được toàn bộ nội dung
- Cách phân tích cú pháp JSON hiện tại có vấn đề kém hiệu quả: không thể làm gì cho đến khi toàn bộ dữ liệu được nhận đầy đủ
- Dữ liệu được chia thành nhiều chunk (phần) theo cách breadth-first, trong đó các phần chưa sẵn sàng được biểu diễn bằng Promise và được lấp dần khi đã sẵn sàng, cho phép client sử dụng cả dữ liệu chưa hoàn thiện
- Khái niệm này là đổi mới cốt lõi của React Server Components (RSC), và kiểm soát trạng thái tải theo từng giai đoạn có chủ đích thông qua
<Suspense>
- Có thể tách biệt việc streaming dữ liệu và luồng tải UI có chủ đích để mang lại trải nghiệm người dùng linh hoạt hơn
Ý tưởng về JPEG lũy tiến và JSON lũy tiến
- JPEG lũy tiến không tải ảnh theo kiểu từ trên xuống dưới trong một lần, mà trước tiên hiển thị toàn bộ ảnh ở trạng thái mờ rồi dần trở nên sắc nét hơn
- Tương tự, áp dụng cách tiếp cận lũy tiến cho việc truyền JSON cho phép sử dụng ngay một phần dữ liệu mà không phải đợi toàn bộ hoàn tất
- Với cấu trúc dữ liệu JSON ví dụ, cách thông thường chỉ có thể parse sau khi đã nhận đến byte cuối cùng
- Vì vậy client phải chờ đến khi mọi thứ được truyền xong, kể cả phần chậm của server (ví dụ: tải
comments từ DB chậm), và đây là tiêu chuẩn hiện tại rất kém hiệu quả
Giới hạn của trình phân tích cú pháp JSON streaming
- Nếu dùng trình phân tích cú pháp JSON streaming thì có thể tạo ra cây đối tượng dữ liệu chưa hoàn chỉnh (trung gian)
- Tuy nhiên, khi các trường của từng đối tượng (ví dụ:
footer, danh sách nhiều comment, v.v.) chỉ được truyền một phần, sẽ phát sinh vấn đề không khớp kiểu và khó xác định đã hoàn tất hay chưa, làm giảm khả năng sử dụng
- Tương tự như render HTML theo kiểu streaming, nếu xử lý stream theo thứ tự thì một phần chậm có thể làm chậm toàn bộ kết quả
- Đây là lý do việc tận dụng JSON streaming nói chung không phổ biến
Đề xuất cấu trúc Progressive JSON
- Thay vì streaming theo kiểu duyệt sâu của cách truyền cũ (tức truyền bằng cách đi sâu vào các nhánh con của cây), mô hình này áp dụng breadth-first
- Chỉ gửi đối tượng cấp cao nhất trước, còn các giá trị con được đặt thành placeholder giống Promise, rồi được điền dần bằng các chunk riêng khi sẵn sàng
- Ví dụ, mỗi khi server hoàn tất việc tải dữ liệu bất đồng bộ thì gửi chunk tương ứng, và client chỉ sử dụng những gì đã sẵn sàng
- Nhờ đó có thể nhận dữ liệu bất đồng bộ (tải sớm) mà không phải chờ toàn bộ nhiều phần chậm xử lý xong
- Nếu client được thiết kế vững vàng cho việc nhận chunk không tuần tự và bán tuần tự, server có thể linh hoạt áp dụng nhiều chiến lược chia chunk khác nhau
Inlining và Outlining: truyền dữ liệu hiệu quả
- Định dạng streaming JSON lũy tiến có thể trích riêng các đối tượng được tái sử dụng (ví dụ: cùng một
userInfo được tham chiếu ở nhiều nơi) thành một chunk duy nhất để các vị trí khác nhau cùng tham chiếu mà không cần lưu trùng lặp
- Chỉ tách phần chậm ra rồi gửi dưới dạng placeholder, còn phần còn lại được điền ngay để tạo luồng dữ liệu hiệu quả
- Khi cùng một đối tượng xuất hiện nhiều lần, có thể chỉ truyền một lần rồi tái sử dụng (Outlining)
- Theo cách này, cả tham chiếu vòng (cấu trúc đối tượng tự tham chiếu chính nó) cũng có thể được serialize tự nhiên bằng cấu trúc tham chiếu gián tiếp giữa các chunk, thay vì gặp khó khăn như JSON thông thường
Triển khai streaming lũy tiến của React Server Components (RSC)
- Trên thực tế, React Server Components là ví dụ tiêu biểu áp dụng mô hình streaming JSON lũy tiến
- Server sử dụng cấu trúc tải dữ liệu bên ngoài (ví dụ:
Post, Comments) theo kiểu bất đồng bộ
- Ở phía client, các phần chưa đến được giữ dưới dạng Promise, và UI được render dần theo thứ tự dữ liệu sẵn sàng
- Thiết lập trạng thái tải có chủ đích bằng
<Suspense> của React
- Để tránh những lần nhảy giao diện không cần thiết gây khó chịu cho trải nghiệm người dùng, trạng thái Promise (các “lỗ trống”) không được hiển thị ngay mà có thể dàn dựng tải theo từng bước bằng
<Suspense> fallback
- Ngay cả khi dữ liệu đến nhanh, nhà phát triển vẫn có thể kiểm soát để UI thực tế được lộ ra dần theo các giai đoạn đã thiết kế
Tóm tắt và hàm ý
- Đổi mới cốt lõi của React Server Components nằm ở cách streaming dần các props của cây component từ ngoài vào trong
- Vì vậy không cần chờ server chuẩn bị xong toàn bộ dữ liệu; có thể hiển thị phần quan trọng trước và đồng thời kiểm soát chi tiết trạng thái chờ tải
- Không chỉ riêng bản thân streaming, mà còn cần hỗ trợ ở cấp mô hình lập trình mang tính cấu trúc như
<Suspense> của React để tận dụng nó
- Nhờ đó có thể giảm bớt các nút thắt cổ chai của cách truyền cũ, như việc một phần dữ liệu chậm làm trì hoãn toàn bộ
1 bình luận
Ý kiến trên Hacker News
JSON.parse