Ngày xuất bản: 6 tháng 2 năm 2019, Ngày cập nhật gần đây nhất: 5 tháng 1 năm 2026
Một trong những quyết định cốt lõi mà nhà phát triển web phải đưa ra là nơi triển khai logic và kết xuất trong ứng dụng của họ. Việc này có thể khó khăn vì có rất nhiều cách để xây dựng một trang web.
Hiểu biết của chúng tôi về không gian này được hình thành dựa trên công việc của chúng tôi trong Chrome khi trao đổi với các trang web lớn trong vài năm qua. Nói chung, chúng tôi khuyến khích các nhà phát triển cân nhắc việc kết xuất phía máy chủ hoặc kết xuất tĩnh thay vì phương pháp gắn kết lại hoàn toàn phương pháp.
Để hiểu rõ hơn về các kiến trúc mà chúng tôi đang lựa chọn khi đưa ra quyết định này, chúng tôi cần có thuật ngữ nhất quán và một khung chung cho từng phương pháp. Sau đó, bạn có thể đánh giá tốt hơn những điểm đánh đổi của từng phương pháp kết xuất theo hiệu suất của trang.
Thuật ngữ
Trước tiên, chúng ta sẽ định nghĩa một số thuật ngữ mà chúng ta sẽ sử dụng.
Kết xuất
- Kết xuất phía máy chủ (SSR)
- Kết xuất một ứng dụng trên máy chủ để gửi HTML thay vì JavaScript đến máy khách.
- Kết xuất phía máy khách (CSR)
- Kết xuất một ứng dụng trong trình duyệt, sử dụng JavaScript để sửa đổi DOM.
- Kết xuất trước
- Chạy một ứng dụng phía máy khách trong thời gian xây dựng để nắm bắt trạng thái ban đầu của ứng dụng dưới dạng HTML tĩnh. Lưu ý: "kết xuất trước" theo nghĩa này khác với tính năng kết xuất trước của trình duyệt đối với các thao tác di chuyển trong tương lai.
- Hút nước
- Chạy tập lệnh phía máy khách để thêm trạng thái ứng dụng và tính tương tác vào HTML được kết xuất phía máy chủ. Tính năng hút nước giả định rằng DOM không thay đổi.
- Gắn kết lại
- Mặc dù thường được dùng để chỉ cùng một ý nghĩa với tính năng hút nước, nhưng tính năng gắn kết lại ngụ ý việc thường xuyên cập nhật DOM bằng trạng thái mới nhất, kể cả sau lần hút nước ban đầu.
Hiệu suất
- Thời gian cho byte đầu tiên (TTFB)
- Thời gian giữa lúc nhấp vào một đường liên kết và byte nội dung đầu tiên tải trên trang mới.
- Hiển thị nội dung đầu tiên (FCP)
- Thời điểm nội dung được yêu cầu (nội dung bài viết, v.v.) trở nên hiển thị.
- Lượt tương tác đến nội dung hiển thị tiếp theo (INP)
- Một chỉ số đại diện đánh giá xem một trang có phản hồi nhanh chóng và nhất quán đối với dữ liệu đầu vào của người dùng hay không.
- Tổng thời gian chặn (TBT)
- Một chỉ số đại diện cho INP tính toán thời gian luồng chính bị chặn trong quá trình tải trang.
Kết xuất phía máy chủ
Kết xuất phía máy chủ tạo ra toàn bộ HTML cho một trang trên máy chủ để phản hồi thao tác di chuyển. Điều này giúp tránh các chuyến đi khứ hồi bổ sung để tìm nạp dữ liệu và tạo mẫu trên máy khách, vì trình kết xuất sẽ xử lý các chuyến đi khứ hồi này trước khi trình duyệt nhận được phản hồi.
Kết xuất phía máy chủ thường tạo ra FCP nhanh. Việc chạy logic trang và kết xuất trên máy chủ giúp bạn tránh gửi nhiều JavaScript đến máy khách. Điều này giúp giảm TTBT của trang, đồng thời có thể dẫn đến INP thấp hơn, vì luồng chính không bị chặn thường xuyên trong quá trình tải trang. Khi luồng chính ít bị chặn hơn, các lượt tương tác của người dùng sẽ có nhiều cơ hội chạy sớm hơn.
Điều này có lý, vì với tính năng kết xuất phía máy chủ, bạn thực sự chỉ gửi văn bản và đường liên kết đến trình duyệt của người dùng. Phương pháp này có thể hoạt động hiệu quả đối với nhiều điều kiện về thiết bị và mạng, đồng thời mở ra các phương pháp tối ưu hoá trình duyệt thú vị, chẳng hạn như phân tích cú pháp tài liệu phát trực tuyến.
Với tính năng kết xuất phía máy chủ, người dùng ít có khả năng phải chờ JavaScript liên kết với CPU chạy trước khi có thể sử dụng trang web của bạn. Ngay cả khi bạn không thể tránh JavaScript của bên thứ ba, việc sử dụng tính năng kết xuất phía máy chủ để giảm chi phí JavaScript của bên thứ nhất có thể giúp bạn có thêm ngân sách cho phần còn lại. Tuy nhiên, có một điểm đánh đổi tiềm ẩn với phương pháp này: việc tạo trang trên máy chủ mất thời gian, điều này có thể làm tăng TTFB của trang.
Việc kết xuất phía máy chủ có đủ cho ứng dụng của bạn hay không phần lớn phụ thuộc vào loại trải nghiệm mà bạn đang xây dựng. Có một cuộc tranh luận kéo dài về các ứng dụng chính xác của tính năng kết xuất phía máy chủ so với tính năng kết xuất phía máy khách, nhưng bạn luôn có thể chọn sử dụng tính năng kết xuất phía máy chủ cho một số trang và không sử dụng cho các trang khác. Một số trang web đã áp dụng thành công các kỹ thuật kết xuất kết hợp. Ví dụ: Netflix kết xuất phía máy chủ các trang đích tương đối tĩnh, đồng thời prefetching JavaScript cho các trang có nhiều lượt tương tác, giúp các trang được kết xuất phía máy khách nặng hơn này có nhiều cơ hội tải nhanh hơn.
Với nhiều khung, thư viện và kiến trúc hiện đại, bạn có thể kết xuất cùng một ứng dụng trên cả máy khách và máy chủ. Bạn có thể sử dụng các kỹ thuật này để kết xuất phía máy chủ. Tuy nhiên, các kiến trúc mà quá trình kết xuất diễn ra cả trên máy chủ và trên máy khách là một lớp giải pháp riêng với các đặc điểm hiệu suất và điểm đánh đổi rất khác nhau. Người dùng React có thể sử dụng API DOM máy chủ hoặc các giải pháp được xây dựng trên các API này như Next.js để kết xuất phía máy chủ. Người dùng Vue có thể sử dụng hướng dẫn kết xuất phía máy chủ của Vue hoặc Nuxt. Angular có Universal.
Tuy nhiên, hầu hết các giải pháp phổ biến đều sử dụng một số hình thức hút nước, vì vậy, hãy lưu ý đến các phương pháp mà công cụ của bạn sử dụng.
Kết xuất tĩnh
Quá trình kết xuất tĩnh diễn ra trong thời gian xây dựng. Phương pháp này mang lại FCP nhanh, đồng thời TBT và INP thấp hơn, miễn là bạn giới hạn lượng JavaScript phía máy khách trên các trang. Không giống như kết xuất phía máy chủ, phương pháp này cũng đạt được TTFB nhanh một cách nhất quán, vì HTML cho một trang không phải được tạo động trên máy chủ. Nói chung, kết xuất tĩnh có nghĩa là tạo một tệp HTML riêng cho từng URL trước thời hạn. Với các phản hồi HTML được tạo trước, bạn có thể triển khai kết xuất tĩnh cho nhiều CDN để tận dụng tính năng lưu vào bộ nhớ đệm ở biên.
Các giải pháp kết xuất tĩnh có đủ hình dạng và kích thước. Các công cụ như Gatsby được thiết kế để giúp nhà phát triển cảm thấy như ứng dụng của họ đang được kết xuất động, chứ không phải được tạo dưới dạng bước xây dựng. Các công cụ tạo trang web tĩnh như 11ty, Jekyll, và Metalsmith tận dụng bản chất tĩnh của chúng, cung cấp một phương pháp dựa trên mẫu hơn.
Một trong những nhược điểm của tính năng kết xuất tĩnh là tính năng này phải tạo các tệp HTML riêng lẻ cho mọi URL có thể có. Điều này có thể gây khó khăn hoặc thậm chí không khả thi khi bạn cần dự đoán trước các URL đó và đối với các trang web có số lượng lớn trang duy nhất.
Người dùng React có thể quen thuộc với Gatsby, tính năng xuất tĩnh Next.js hoặc Navi. Tất cả các tính năng này đều giúp bạn dễ dàng tạo trang từ các thành phần. Tuy nhiên, tính năng kết xuất tĩnh và kết xuất trước hoạt động khác nhau: các trang được kết xuất tĩnh có tính tương tác mà không cần thực thi nhiều JavaScript phía máy khách, trong khi tính năng kết xuất trước cải thiện FCP của Ứng dụng trang đơn phải được khởi động trên máy khách để các trang thực sự có tính tương tác.
Nếu bạn không chắc chắn liệu một giải pháp nhất định là kết xuất tĩnh hay kết xuất trước, hãy thử tắt JavaScript và tải trang bạn muốn kiểm tra. Đối với các trang được kết xuất tĩnh, hầu hết các tính năng tương tác vẫn tồn tại mà không cần JavaScript. Các trang được kết xuất trước vẫn có thể có một số tính năng cơ bản như đường liên kết khi JavaScript bị tắt, nhưng hầu hết trang đều không hoạt động.
Một bài kiểm tra hữu ích khác là sử dụng tính năng điều tiết mạng trong Chrome DevTools và xem lượng JavaScript tải xuống trước khi một trang trở nên có tính tương tác. Tính năng kết xuất trước thường cần nhiều JavaScript hơn để trở nên có tính tương tác và đó JavaScript có xu hướng phức tạp hơn cải tiến tăng dần phương pháp được sử dụng trong kết xuất tĩnh.
Kết xuất phía máy chủ so với kết xuất tĩnh
Kết xuất phía máy chủ không phải là giải pháp tốt nhất cho mọi thứ, vì bản chất
động của nó có thể gây ra chi phí tính toán đáng kể. Nhiều giải pháp kết xuất phía máy chủ không xả sớm, trì hoãn TTFB hoặc tăng gấp đôi dữ liệu được gửi (ví dụ: trạng thái nội tuyến do JavaScript sử dụng trên máy khách). Trong React,
renderToString() có thể chậm vì đây là phương thức đồng bộ và đơn luồng.
Các API DOM máy chủ React mới hơn
hỗ trợ phát trực tuyến, có thể giúp trình duyệt nhận được phần ban đầu của phản hồi HTML sớm hơn trong khi phần còn lại vẫn đang được tạo trên máy chủ.
Để kết xuất phía máy chủ "đúng cách", bạn có thể phải tìm hoặc xây dựng một giải pháp cho tính năng lưu vào bộ nhớ đệm thành phần, quản lý mức tiêu thụ bộ nhớ, sử dụng kỹ thuật ghi nhớ, và các vấn đề khác. Bạn thường xử lý hoặc xây dựng lại cùng một ứng dụng hai lần, một lần trên máy khách và một lần trên máy chủ. Việc kết xuất phía máy chủ hiển thị nội dung sớm hơn không nhất thiết giúp bạn giảm bớt công việc phải làm. Nếu bạn có nhiều việc phải làm trên máy khách sau khi phản hồi HTML do máy chủ tạo đến máy khách, thì điều này vẫn có thể dẫn đến TBT và INP cao hơn cho trang web của bạn.
Kết xuất phía máy chủ tạo ra HTML theo yêu cầu cho từng URL, nhưng có thể chậm hơn so với việc chỉ phân phát nội dung được kết xuất tĩnh. Nếu bạn có thể thực hiện thêm công việc, thì tính năng kết xuất phía máy chủ cộng với tính năng lưu vào bộ nhớ đệm HTML có thể giảm đáng kể thời gian kết xuất máy chủ. Ưu điểm của tính năng kết xuất phía máy chủ là khả năng kéo thêm dữ liệu "trực tiếp" và phản hồi một tập hợp yêu đủ hơn so với khả năng kết xuất tĩnh. Các trang cần cá nhân hoá là một ví dụ cụ thể về loại yêu cầu không hoạt động tốt với tính năng kết xuất tĩnh.
Kết xuất phía máy chủ cũng có thể đưa ra các quyết định thú vị khi xây dựng một PWA. Nên sử dụng tính năng lưu vào bộ nhớ đệm của trình chạy dịch vụ toàn trang hay kết xuất phía máy chủ từng phần nội dung riêng lẻ?
Kết xuất phía máy khách
Kết xuất phía máy khách có nghĩa là kết xuất các trang trực tiếp trong trình trình duyệt bằng JavaScript. Tất cả logic, tìm nạp dữ liệu, tạo mẫu và định tuyến đều được xử lý trên máy khách thay vì trên máy chủ. Kết quả hiệu quả là nhiều dữ liệu được truyền đến thiết bị của người dùng từ máy chủ và điều đó đi kèm với một tập hợp các điểm đánh đổi riêng.
Kết xuất phía máy khách có thể khó thực hiện và duy trì tốc độ nhanh cho thiết bị di động.
Với một chút công sức để duy trì ngân sách JavaScript chặt chẽ
và mang lại giá trị trong ít chuyến đi khứ hồi
nhất có thể, bạn có thể khiến kết xuất phía máy khách gần như sao chép
hiệu suất của kết xuất phía máy chủ thuần tuý. Bạn có thể giúp trình phân tích cú pháp hoạt động
nhanh hơn bằng cách phân phối các tập lệnh và dữ liệu quan trọng bằng <link rel=preload>
Bạn cũng nên cân nhắc sử dụng các mẫu như PRPL
để đảm bảo rằng các thao tác di chuyển ban đầu và tiếp theo diễn ra tức thì.
Nhược điểm chính của tính năng kết xuất phía máy khách là lượng JavaScript cần thiết có xu hướng tăng khi ứng dụng phát triển, điều này có thể ảnh hưởng đến INP của trang. Điều này trở nên đặc biệt khó khăn khi thêm các thư viện JavaScript mới, polyfill và mã của bên thứ ba, cạnh tranh về sức mạnh xử lý và thường phải được xử lý trước khi nội dung của trang có thể kết xuất.
Những trải nghiệm sử dụng tính năng kết xuất phía máy khách và dựa vào các gói JavaScript lớn nên cân nhắc việc chia tách mã mạnh mẽ để giảm TBT và INP trong quá trình tải trang, cũng như tải JavaScript chậm để chỉ phân phát những gì người dùng cần, khi cần. Đối với những trải nghiệm có ít hoặc không có tính tương tác, kết xuất phía máy chủ có thể là một giải pháp có khả năng mở rộng hơn cho những vấn đề này.
Đối với những người xây dựng ứng dụng trang đơn, việc xác định các phần cốt lõi của giao diện người dùng do hầu hết các trang chia sẻ cho phép bạn áp dụng kỹ thuật lưu vào bộ nhớ đệm của vỏ ứng dụng. Kết hợp với trình chạy dịch vụ, điều này có thể cải thiện đáng kể
hiệu suất cảm nhận trong các lượt truy cập lặp lại, vì trang có thể tải HTML và các phần phụ thuộc của vỏ ứng dụng từ CacheStorage rất nhanh.
Tính năng gắn kết lại kết hợp kết xuất phía máy chủ và phía máy khách
Tính năng hút nước là một phương pháp giúp giảm thiểu các điểm đánh đổi giữa kết xuất phía máy khách và kết xuất phía máy chủ bằng cách thực hiện cả hai. Các yêu cầu di chuyển, chẳng hạn như tải hoặc tải lại toàn trang, được xử lý bởi một máy chủ kết xuất ứng dụng thành HTML. Sau đó, JavaScript và dữ liệu được dùng để kết xuất sẽ được nhúng vào tài liệu kết quả. Khi được thực hiện cẩn thận, điều này sẽ đạt được FCP nhanh như kết xuất phía máy chủ, sau đó "chọn" bằng cách kết xuất lại trên máy khách.
Đây là một giải pháp hiệu quả, nhưng có thể có những nhược điểm đáng kể về hiệu suất.
Nhược điểm chính của tính năng kết xuất phía máy chủ với tính năng gắn kết lại là tính năng này có thể có tác động tiêu cực đáng kể đến TBT và INP, ngay cả khi cải thiện FCP. Các trang được kết xuất phía máy chủ có thể xuất hiện như đã tải và có tính tương tác, nhưng thực sự không thể phản hồi dữ liệu đầu vào cho đến khi các tập lệnh phía máy khách cho các thành phần được thực thi và trình xử lý sự kiện đã được đính kèm. Trên thiết bị di động, quá trình này có thể mất vài phút, gây nhầm lẫn và khó chịu cho người dùng.
Vấn đề về gắn kết lại: một ứng dụng với giá của hai ứng dụng
Để JavaScript phía máy khách tiếp quản chính xác nơi máy chủ dừng lại, mà không cần yêu cầu lại tất cả dữ liệu mà máy chủ đã kết xuất HTML, hầu hết các giải pháp kết xuất phía máy chủ đều tuần tự hoá phản hồi từ các phần phụ thuộc dữ liệu của giao diện người dùng dưới dạng thẻ tập lệnh trong tài liệu. Vì điều này sao chép nhiều HTML, nên tính năng gắn kết lại có thể gây ra nhiều vấn đề hơn là chỉ trì hoãn tính tương tác.
Máy chủ đang trả về nội dung mô tả về giao diện người dùng của ứng dụng để phản hồi yêu cầu di chuyển, nhưng cũng đang trả về dữ liệu nguồn được dùng để tạo giao diện người dùng đó
và bản sao hoàn chỉnh của quá trình triển khai giao diện người dùng, sau đó khởi động trên máy khách. Giao diện người dùng không trở nên có tính tương tác cho đến sau khi bundle.js hoàn tất quá trình
tải và thực thi.
Các chỉ số hiệu suất được thu thập từ các trang web thực bằng cách sử dụng tính năng kết xuất phía máy chủ và gắn kết lại cho thấy rằng đây hiếm khi là lựa chọn tốt nhất. Lý do quan trọng nhất là tác động của nó đến trải nghiệm người dùng, khi một trang trông có vẻ đã sẵn sàng nhưng không có tính năng tương tác nào của nó hoạt động.
Có hy vọng về tính năng kết xuất phía máy chủ với tính năng gắn kết lại. Trong ngắn hạn, chỉ sử dụng tính năng kết xuất phía máy chủ cho nội dung có khả năng lưu vào bộ nhớ đệm cao có thể giảm TTFB, tạo ra kết quả tương tự như kết xuất trước. Việc gắn kết lại tăng dần, liên tục hoặc một phần có thể là chìa khoá để giúp kỹ thuật này khả thi hơn trong tương lai.
Phát trực tuyến kết xuất phía máy chủ và gắn kết lại tăng dần
Tính năng kết xuất phía máy chủ đã có một số bước phát triển trong vài năm qua.
Tính năng phát trực tuyến kết xuất phía máy chủ
cho phép bạn gửi HTML theo các khối mà trình duyệt có thể kết xuất tăng dần khi nhận được. Điều này có thể giúp người dùng nhận được mã đánh dấu nhanh hơn, tăng tốc FCP. Trong
React, các luồng không đồng bộ trong renderToPipeableStream(), so với
đồng bộ renderToString(), có nghĩa là áp suất ngược được xử lý tốt.
Gắn kết lại tăng dần cũng đáng cân nhắc (React đã triển khai tính năng này). Với phương pháp này, các phần riêng lẻ của ứng dụng được kết xuất phía máy chủ sẽ được "khởi động" theo thời gian, thay vì phương pháp phổ biến hiện tại là khởi chạy toàn bộ ứng dụng cùng một lúc. Điều này có thể giúp giảm lượng JavaScript cần thiết để làm cho các trang có tính tương tác, vì cho phép bạn trì hoãn việc nâng cấp phía máy khách của các phần có mức độ ưu tiên thấp của trang để ngăn chặn việc chặn luồng chính, cho phép các lượt tương tác của người dùng diễn ra sớm hơn sau khi người dùng bắt đầu.
Tính năng gắn kết lại tăng dần cũng có thể giúp bạn tránh một trong những cạm bẫy gắn kết lại kết xuất phía máy chủ phổ biến nhất: cây DOM được kết xuất phía máy chủ bị huỷ và sau đó được xây dựng lại ngay lập tức, thường là do quá trình kết xuất phía máy khách đồng bộ ban đầu yêu cầu dữ liệu chưa sẵn sàng, thường là Promise chưa được phân giải.
Gắn kết lại một phần
Tính năng gắn kết lại một phần đã chứng tỏ là khó triển khai. Phương pháp này là phần mở rộng của tính năng gắn kết lại tăng dần, phân tích các phần riêng lẻ của trang (thành phần, khung hiển thị hoặc cây) và xác định các phần có ít tính tương tác hoặc không có tính phản ứng. Đối với mỗi phần hầu hết là tĩnh này, mã JavaScript tương ứng sẽ được chuyển đổi thành các tham chiếu không hoạt động và các tính năng trang trí, giảm dấu vết phía khách hàng của chúng xuống gần bằng 0.
Phương pháp gắn kết lại một phần đi kèm với các vấn đề và điểm đánh đổi riêng. Phương pháp này đặt ra một số thách thức thú vị cho việc lưu vào bộ nhớ đệm và thao tác di chuyển phía máy khách có nghĩa là chúng ta không thể giả định rằng HTML được kết xuất phía máy chủ cho các phần không hoạt động của ứng dụng có sẵn mà không cần tải toàn bộ trang.
Kết xuất ba hình thái
Nếu trình chạy dịch vụ là một lựa chọn cho bạn, hãy cân nhắc kết xuất ba hình thái. Kỹ thuật này cho phép bạn sử dụng tính năng phát trực tuyến kết xuất phía máy chủ cho các thao tác di chuyển ban đầu hoặc không phải JavaScript điều hướng, sau đó để trình chạy dịch vụ đảm nhận việc kết xuất HTML cho điều hướng sau khi đã cài đặt. Điều này có thể giúp các thành phần và mẫu được lưu vào bộ nhớ đệm luôn được cập nhật và cho phép các thao tác di chuyển theo kiểu SPA để kết xuất khung hiển thị mới trong cùng một phiên. Phương pháp này hoạt động hiệu quả nhất khi bạn có thể chia sẻ cùng một mã tạo mẫu và định tuyến giữa máy chủ, trang máy khách và trình chạy dịch vụ.
Cân nhắc về SEO
Khi chọn chiến lược kết xuất web, các nhóm thường cân nhắc tác động của SEO. Kết xuất phía máy chủ là một lựa chọn phổ biến để mang lại trải nghiệm "hoàn chỉnh" mà trình thu thập dữ liệu có thể diễn giải. Trình thu thập dữ liệu có thể hiểu JavaScript, nhưng thường có những hạn chế về cách chúng kết xuất. Kết xuất phía máy khách có thể hoạt động, nhưng thường cần kiểm tra và chi phí bổ sung. Gần đây, kết xuất động cũng trở thành một lựa chọn đáng cân nhắc nếu kiến trúc của bạn phụ thuộc nhiều vào JavaScript phía máy khách.
Kết luận
Khi quyết định một phương pháp kết xuất, hãy đo lường và hiểu rõ những điểm nghẽn của bạn. Cân nhắc xem liệu kết xuất tĩnh hay kết xuất phía máy chủ có thể giúp bạn đạt được hầu hết mục tiêu hay không. Bạn có thể chủ yếu phân phối HTML với JavaScript tối thiểu để có trải nghiệm tương tác. Dưới đây là một biểu đồ thông tin hữu ích cho thấy phổ máy chủ-máy khách:
Ghi công
Cảm ơn mọi người đã đánh giá và truyền cảm hứng:
Jeffrey Posnick, Houssein Djirdeh, Shubhie Panicker, Chris Harrelson và Sebastian Markbåge.