Chỉ cung cấp các phần phụ thuộc theo hướng dữ liệu khi chúng cần
Điều gì về các nhánh mã không tĩnh qua các lần tải trang? Ví dụ: gửi xuống tất cả mã hiển thị cho tất cả các loại và kết hợp thành phần khác nhau cho các bài đăng trên News Feed sẽ làm tăng kích thước JavaScript của trang lên đáng kể.
Những phụ thuộc này được quyết định trong thời gian chạy, dựa trên dữ liệu đó được trả về từ back end. Điều này cho phép chúng tôi sử dụng một tính năng mới của Relay để thể hiện mã kết xuất nào là cần thiết, tùy thuộc vào loại dữ liệu được trả về. Nếu bài đăng có tệp đính kèm đặc biệt, chẳng hạn như ảnh, chúng tôi mô tả rằng chúng tôi cần PhotoComponent để hiển thị ảnh đó.
... on Post {
... on PhotoPost {
@module('PhotoComponent.js')
photo_data
}
... on VideoPost {
@module('VideoComponent.js')
video_data
}
}
Chúng tôi thể hiện các phụ thuộc cần thiết để hiển thị từng loại bài đăng như một phần của truy vấn.
Thậm chí tốt hơn, PhotoComponentbản thân nó mô tả chính xác dữ liệu nào trên loại tệp đính kèm ảnh mà nó cần dưới dạng một đoạn, có nghĩa là chúng ta thậm chí có thể tách ra logic truy vấn.
Sử dụng ngân sách JavaScript để ngăn chặn lỗi mã
Các lớp và phần phụ thuộc có điều kiện giúp chúng tôi chỉ cung cấp mã cần thiết cho mỗi giai đoạn, nhưng chúng tôi cũng cần đảm bảo kích thước của mỗi lớp luôn được kiểm soát theo thời gian. Để quản lý điều này, chúng tôi đã giới thiệu ngân sách JavaScript cho mỗi sản phẩm.
Chúng tôi đặt ngân sách dựa trên mục tiêu hiệu suất, hạn chế kỹ thuật và cân nhắc sản phẩm. Chúng tôi đã phân bổ ngân sách cấp trang và chia nhỏ trang dựa trên ranh giới sản phẩm và ranh giới nhóm. Cơ sở hạ tầng dùng chung được thêm vào danh sách được tuyển chọn cẩn thận và có ngân sách riêng. Cơ sở hạ tầng được chia sẻ tính vào ngân sách của tất cả các trang, nhưng các mô-đun bên trong nó được miễn phí cho các nhóm sản phẩm sử dụng. Chúng tôi cũng có ngân sách cho mã được trả chậm, tải có điều kiện hoặc tải khi tương tác.
Chúng tôi đã tạo công cụ bổ sung cho từng bước của quy trình:
- Công cụ đồ thị phụ thuộc giúp bạn dễ dàng hiểu byte đến từ đâu và xác định các cơ hội để giảm kích thước mã.
- Giám sát kích thước trên các yêu cầu hợp nhất hiển thị các cải tiến / hồi quy kích thước và kích hoạt các cảnh báo có thể tùy chỉnh.
- Biểu đồ tương tác hiển thị kích thước lịch sử và mọi thứ đã thay đổi như thế nào giữa các lần sửa đổi.
- Trang tổng quan giúp chúng tôi hiểu trạng thái hiện tại của quy mô liên quan đến ngân sách.
Hiện đại hóa việc tìm nạp dữ liệu để lấy nó sớm nhất có thể
Là một phần của quá trình xây dựng lại này, chúng tôi đã hiện đại hóa cơ sở hạ tầng tìm nạp dữ liệu của mình trên web. Mặc dù một số tính năng của trang web cũ sử dụng Relay và GraphQL để tìm nạp dữ liệu, nhưng hầu hết dữ liệu được tìm nạp đặc biệt như một phần của kết xuất PHP phía máy chủ của chúng. Với trang web mới, chúng tôi đã có thể chuẩn hóa với các ứng dụng dành cho thiết bị di động của mình và đảm bảo rằng tất cả việc tìm nạp dữ liệu đều thông qua GraphQL. Vì Relay và GraphQL đã xử lý công việc “ít nhất có thể” cho chúng tôi, chúng tôi chỉ cần thực hiện một số thay đổi để hỗ trợ nhận được dữ liệu chúng tôi cần sớm nhất có thể.
Tải trước dữ liệu theo yêu cầu máy chủ ban đầu để cải thiện khởi động
Nhiều ứng dụng web cần phải đợi cho đến khi tất cả JavaScript của chúng được tải xuống và thực thi trước khi tìm nạp dữ liệu từ máy chủ. Với Relay, chúng tôi biết trang cần dữ liệu gì. Điều này có nghĩa là ngay sau khi máy chủ của chúng tôi nhận được yêu cầu cho một trang, nó có thể bắt đầu chuẩn bị ngay dữ liệu cần thiết và tải xuống song song với mã được yêu cầu. Chúng tôi truyền trực tuyến dữ liệu này với trang khi nó có sẵn để khách hàng có thể tránh các chuyến đi vòng bổ sung và hiển thị nội dung trang cuối cùng sớm hơn.
Truyền dữ liệu cho ít chuyến đi khứ hồi hơn và tương tác tốt hơn
Trong lần tải đầu tiên của Facebook.com, một số nội dung ban đầu có thể bị ẩn hoặc hiển thị bên ngoài khung nhìn. Ví dụ: hầu hết các màn hình phù hợp với một hoặc hai bài đăng trên News Feed, nhưng chúng tôi không biết trước bao nhiêu màn hình sẽ phù hợp. Ngoài ra, rất có thể người dùng sẽ cuộn và sẽ mất thời gian để tìm nạp từng câu chuyện riêng lẻ trong một chuyến khứ hồi nối tiếp. Mặt khác, chúng tôi tìm nạp càng nhiều câu chuyện trong một truy vấn, thì truy vấn đó càng chậm, dẫn đến thời gian truy vấn lâu hơn và thời gian Toàn bộ trực quan lâu hơn cho ngay cả câu chuyện đầu tiên.
Để giải quyết vấn đề này, chúng tôi sử dụng tiện ích mở rộng GraphQL nội bộ @stream, để truyền trực tuyến kết nối nguồn cấp dữ liệu đến máy khách cho cả lần tải ban đầu và phân trang tiếp theo khi cuộn. Điều này cho phép chúng tôi gửi từng câu chuyện nguồn cấp dữ liệu ngay khi nó sẵn sàng, từng câu chuyện một, chỉ với một thao tác truy vấn duy nhất.
fragment HomepageData on User {
newsFeed(first: 10) {
edges @stream
}
...AdditionalData
}
Trì hoãn dữ liệu không cần thiết ngay lập tức
Các phần khác nhau của các truy vấn nhất định mất nhiều thời gian để tính toán hơn các phần khác. Ví dụ: khi xem hồ sơ, việc tìm nạp tên và ảnh hồ sơ của một người tương đối nhanh nhưng sẽ mất nhiều thời gian hơn một chút để tìm nạp nội dung của Dòng thời gian của họ.
Để tìm nạp cả hai loại dữ liệu với một truy vấn duy nhất, chúng tôi sử dụng @defer, điều này cho phép các phần khác nhau của phản hồi được truyền trực tuyến ngay khi chúng sẵn sàng. Điều này cho phép chúng tôi hiển thị phần lớn giao diện người dùng với dữ liệu ban đầu nhanh nhất có thể và hiển thị trạng thái tải cho phần còn lại. Với React Suspense , điều này thậm chí còn dễ dàng hơn, vì chúng tôi có thể tạo các trạng thái tải một cách rõ ràng để đảm bảo trải nghiệm tải trang từ trên xuống mượt mà.
fragment ProfileData on User {
name
profile_picture { ... }
...AdditionalData @defer
}