Ngày xuất bản: Ngày 6 tháng 2 năm 2019, Ngày cập nhật gần đây nhất: Ngày 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ọ. Điều này có thể khó khăn vì có rất nhiều cách để xây dựng một trang web.
Sự hiểu biết của chúng tôi về không gian này được hình thành từ công việc của chúng tôi trong Chrome khi trò chuyện 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 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 bù nước hoàn toàn.
Để hiểu rõ hơn về các cấu trúc mà chúng ta đang lựa chọn khi đưa ra quyết định này, chúng ta 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 từ góc độ hiệu suất trang.
Thuật ngữ
Trước tiên, chúng ta sẽ định nghĩa một số thuật ngữ sẽ sử dụng.
Kết xuất
- Kết xuất phía máy chủ (SSR)
- Kết xuấ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)
- Hiển thị ứng dụng trong trình duyệt, sử dụng JavaScript để sửa đổi DOM.
- Kết xuất trước
- Chạy ứng dụng phía máy khách tại thời điểm xây dựng để ghi lại trạng thái ban đầu của ứng dụng dưới dạng HTML tĩnh. Lưu ý rằng "kết xuất trước" theo nghĩa này khác với kết xuất trước trình duyệt của các thao tác điều hướng 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à khả năng tương tác vào HTML do máy chủ kết xuất. Quá trình hydrat hoá giả định rằng DOM không thay đổi.
- Bù nước
- Mặc dù thường được dùng để chỉ cùng một khái niệm với quá trình hydrat hoá, nhưng quá trình bù nước ngụ ý việc cập nhật DOM thường xuyên bằng trạng thái mới nhất, bao gồm cả sau quá trình hydrat hoá ban đầu.
Hiệu suất
- Thời gian cho byte đầu tiên (TTFB)
- Thời gian từ khi nhấp vào một đường liên kết đến khi byte nội dung đầu tiên tải trên trang mới.
- Nội dung đầu tiên hiển thị (FCP)
- Thời điểm nội dung được yêu cầu (nội dung bài viết, v.v.) xuất hiện.
- 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 và nhất quán với hoạt động đầ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ủ
Tính năng kết xuất phía máy chủ tạo ra HTML đầy đủ cho một trang trên máy chủ để phản hồi thao tác điều hướng. Điều này giúp tránh các lượt khứ hồi bổ sung để tìm nạp dữ liệu và tạo mẫu trên ứng dụng, vì trình kết xuất sẽ xử lý các lượt này trước khi trình duyệt nhận được phản hồi.
Tính năng 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 TBT của trang, đồng thời cũng có thể làm giảm INP 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 hoạt động 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 là hợp 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ả trong nhiều điều kiện mạng và thiết bị, đồng thời mở ra các tính năng 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 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 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ủ cần có 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ụ thuộc phần lớn 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ề việc áp dụng đúng cách kết xuất phía máy chủ so với kết xuất phía máy khách, nhưng bạn luôn có thể chọn sử dụng kết xuất phía máy chủ cho một số trang chứ không phải các trang khác. Một số trang web đã áp dụng thành công kỹ thuật kết xuất kết hợp. Ví dụ: Netflix kết xuất phía máy chủ cho các trang đích tương đối tĩnh, đồng thời prefetching JavaScript cho các trang có nhiều hoạt động tương tác, giúp các trang nặng hơn được kết xuất phía máy khách này có cơ hội tải nhanh hơn.
Với nhiều khung, thư viện và cấu 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 cấu trúc mà quá trình kết xuất diễn ra trên cả máy chủ và máy khách là một loại giải pháp riêng có các đặc điểm hiệu suất và sự đánh đổi rất khác nhau. Người dùng React có thể sử dụng API DOM của máy chủ hoặc các giải pháp được xây dựng trên đó 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 hydrat hoá, 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.
Hiển thị tĩnh
Kết xuất tĩnh diễn ra tại thời điểm xây dựng. Phương pháp này mang lại FCP nhanh, cũng như 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 của mình. 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 và nhất quán vì HTML của một trang không cần 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 trước một tệp HTML riêng cho mỗi URL. 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 bộ nhớ đệm biên.
Các giải pháp cho việc 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 linh động, chứ không phải được tạo dưới dạng một 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 nhiề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à 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ể 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 riêng biệt.
Người dùng React có thể đã quen thuộc với Gatsby, Next.js static export hoặc Navi, tất cả đều giúp bạn dễ dàng tạo trang từ các thành phần. Tuy nhiên, kết xuất tĩnh và kết xuất trước hoạt động theo cách 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 kết xuất trước cải thiện FCP của một Ứng dụng trang đơn phải được khởi động trên máy khách để làm cho các trang thực sự có tính tương tác.
Nếu bạn không chắc 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 mà 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 thử nghiệm hữu ích khác là sử dụng tính năng hạn chế băng thông mạng trong Chrome DevTools và xem lượng JavaScript tải xuống trước khi trang có thể tương tác. Quá trình kết xuất trước thường cần nhiều JavaScript hơn để có thể tương tác và JavaScript đó có xu hướng phức tạp hơn phương pháp cải tiến tăng dần được dùng trong quá trình 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 trường hợp, vì tính chất động của giải pháp này có thể làm tăng đáng kể chi phí điện toán. Nhiều giải pháp kết xuất phía máy chủ không xoá 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 cùng dòng mà 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ợ tính năng truyền trực tuyến, có thể đưa phần đầu của phản hồi HTML đến trình duyệt 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ể cần tìm hoặc xây dựng một giải pháp cho 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 tạo 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ủ cho thấy 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.
Tính năng kết xuất phía máy chủ tạo ra HTML theo yêu cầu cho mỗi 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ể nỗ lực thêm, thì việc kết xuất phía máy chủ cộng với lưu HTML vào bộ nhớ đệm có thể giảm đáng kể thời gian kết xuất của máy chủ. Ưu điểm của việc kết xuất phía máy chủ là khả năng lấy thêm dữ liệu "trực tiếp" và phản hồi một tập hợp yêu cầu đầy đủ hơn so với việc 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 hiệu quả với tính năng kết xuất tĩnh.
Tính năng 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 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 từng phần nội dung trên máy chủ?
Hiển thị 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 ngay trong 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ả thực tế là nhiều dữ liệu hơn được chuyể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 số đánh đổi.
Quá trình kết xuất phía máy khách có thể khó thực hiện và khó duy trì tốc độ nhanh cho thiết bị di động.
Chỉ cần nỗ lực một chút để duy trì ngân sách JavaScript chặt chẽ và mang lại giá trị trong ít vòng lặp nhất có thể, bạn có thể khiến quá trình kết xuất phía máy khách gần như sao chép hiệu suất của quá trình kết xuất thuần tuý phía máy chủ. 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 điều hướng ban đầu và tiếp theo đều diễn ra tức thì.
Nhược điểm chính của việc kết xuất phía máy khách là lượng JavaScript cần thiết có xu hướng tăng lên 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 đặc biệt khó khăn khi có thêm các thư viện JavaScript, polyfill và mã của bên thứ ba mới, những mã này 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ể hiển thị.
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 phân tách mã linh hoạt để giảm TBT và INP trong quá trình tải trang, cũng như tải từng phần JavaScript để chỉ phân phát nội dung mà 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, việ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 cao 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 mà hầu hết các trang đều có cho phép bạn áp dụng kỹ thuật lưu giao diện ứng dụng vào bộ nhớ đệm. Khi kết hợp với trình chạy dịch vụ, tính năng này có thể cải thiện đáng kể
hiệu suất nhận biết được trong các lượt truy cập lặp lại, vì trang có thể tải
HTML của giao diện ứng dụng và các phần phụ thuộc từ CacheStorage rất nhanh.
Quá trình tái tạo kết hợp kết xuất phía máy chủ và kết xuất phía máy khách
Hydration là một phương pháp giúp giảm thiểu sự đánh đổi giữa việc kết xuất phía máy khách và phía máy chủ bằng cách thực hiện cả hai. Các yêu cầu điều hướng, chẳng hạn như tải toàn bộ trang hoặc tải lại, đượ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 dùng để kết xuất sẽ được nhúng vào tài liệu thu được. Khi được thực hiện cẩn thận, phương pháp này sẽ đạt được FCP nhanh như kết xuất phía máy chủ, sau đó "tiếp tục" 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ể gây ra những hạn chế đáng kể về hiệu suất.
Nhược điểm chính của việc kết xuất phía máy chủ bằng tính năng bù nước là 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 dưới dạng đã tải và có tính tương tác, nhưng không thể thực sự 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, khiến người dùng bối rối và thất vọng.
Vấn đề về quá trình bù nước: Một ứng dụng cho 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 chuyển đổi tuần tự 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ì việc này sao chép nhiều HTML, nên quá trình tái tạo có thể gây ra nhiều vấn đề hơn là chỉ làm chậm khả năng tương tác.
Máy chủ sẽ 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 điều hướng, nhưng cũng trả về dữ liệu nguồn dùng để tạo giao diện người dùng đó và một 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 thể tương tác cho đến khi bundle.js tải và thực thi xong.
Các chỉ số hiệu suất được thu thập từ các trang web thực tế sử dụng tính năng kết xuất phía máy chủ và bù nước cho thấy đây hiếm khi là lựa chọn tốt nhất. Lý do quan trọng nhất là ảnh hưởng của chỉ số này đối với trải nghiệm người dùng, khi một trang có vẻ đã sẵn sàng nhưng không có tính năng tương tác nào hoạt động.
Có hy vọng cho việc kết xuất phía máy chủ bằng cách tái cấp nước. Trong ngắn hạn, việc 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ể làm giảm TTFB, mang lại kết quả tương tự như kết xuất trước. Việc tái tạo nước tăng dần, tăng dần hoặc một phần có thể là chìa khoá giúp kỹ thuật này trở nên khả thi hơn trong tương lai.
Kết xuất phía máy chủ trực tuyến và khôi phục dần dần
Tính năng kết xuất phía máy chủ đã có một số điểm phát triển trong vài năm qua.
Kết xuất phía máy chủ trực tuyến cho phép bạn gửi HTML theo từng phần mà trình duyệt có thể kết xuất dần 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ừ đó tăng tốc FCP. Trong React, các luồng không đồng bộ trong renderToPipeableStream(), so với renderToString() đồng bộ, có nghĩa là áp suất ngược được xử lý tốt.
Bạn cũng nên cân nhắc quá trình tái tạo dần dần (React đã triển khai quá trình này). Với phương pháp này, các phần riêng lẻ của ứng dụng do máy chủ kết xuất sẽ được "khởi động" theo thời gian, thay vì phương pháp phổ biến hiện nay 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 để giúp 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 trang chặn luồng chính, cho phép các hoạt động 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.
Quá trình tái tạo dần dần cũng có thể giúp bạn tránh được một trong những lỗi tái tạo phổ biến nhất khi kết xuất phía máy chủ: cây DOM do máy chủ kết xuất bị huỷ rồi ngay lập tức được tạo lại, thường là do quá trình kết xuất đồng bộ ban đầu phía máy khách yêu cầu dữ liệu chưa sẵn sàng, thường là một Promise chưa được giải quyết.
Bù nước một phần
Quá trình tái tạo một phần đã được chứng minh là khó triển khai. Phương pháp này là một phần mở rộng của quá trình tái hydrat hoá tăng dần, giúp phân tích từng phần của trang (thành phần, khung hiển thị hoặc cây) và xác định những phần có ít tính tương tác hoặc không có khả năng phản ứng. Đối với mỗi phần chủ yếu là tĩnh này, mã JavaScript tương ứng sau đó sẽ được chuyển đổi thành các tham chiếu trơ và các tính năng trang trí, giúp giảm mức sử dụng tài nguyên phía máy khách xuống gần như bằng không.
Phương pháp tái tạo một phần cũng có những vấn đề và hạn chế riêng. Điều này đặt ra một số thách thức thú vị cho việc lưu vào bộ nhớ đệm và việc điều hướng phía máy khách có nghĩa là chúng ta không thể giả định rằng HTML do máy chủ kết xuất cho các phần không hoạt động của ứng dụng sẽ có sẵn mà không cần tải toàn bộ trang.
Kết xuất Trisomorphic
Nếu bạn có thể sử dụng trình chạy dịch vụ, hãy cân nhắc việc kết xuất trisomorphic. Kỹ thuật này cho phép bạn sử dụng tính năng kết xuất phía máy chủ trực tuyến cho các thao tác điều hướng ban đầu hoặc không phải JavaScript, sau đó yêu cầu trình chạy dịch vụ đảm nhận việc kết xuất HTML cho các thao tác đ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, đồng thời cho phép điều hướng theo kiểu SPA để hiển thị các chế độ xem 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 ứng dụng và trình chạy dịch vụ.
Những điều cần cân nhắc về SEO
Khi chọn chiến lược kết xuất web, các nhóm thường xem xét 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ó giới hạn về cách trình thu thập dữ liệu kết xuất JavaScript. Tính năng kết xuất phía máy khách có thể hoạt động, nhưng thường cần thêm thử nghiệm và chi phí hao tổn. 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 cấu 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 phương pháp kết xuất, hãy đo lường và tìm hiểu xem điểm tắc nghẽn của bạn là gì. Hãy cân nhắc xem liệu chế độ 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 cung cấp HTML với JavaScript tối thiểu để có được trải nghiệm tương tác. Sau đây là bản đồ hoạ 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.