SydexaSydexa
Trang chủKhoá họcBài viết
Chuyện gì thực sự xảy ra ở trình duyệt sau khi nhấn F5?
Frontend

Chuyện gì thực sự xảy ra ở trình duyệt sau khi nhấn F5?

Hải Phương
|
11/03/2026
|
11 phút đọc

Trong lập trình frontend, "làm mới trang" trông có vẻ là một thao tác đơn giản, nhưng ẩn sau đó là một luồng phối hợp phức tạp giữa giao tiếp mạng (network communication), chiến lược cache (caching strategy) và engine render (rendering engine). Đặc biệt là khi nhấn F5, nó không phải là "tải lại hoàn toàn", cũng không phải là "dùng trực tiếp cache ở local", mà là một cơ chế xác thực thông minh nằm giữa hai trạng thái này. Để thực sự làm chủ các kỹ năng tối ưu hóa hiệu năng và debug frontend, bạn bắt buộc phải hiểu sâu về quá trình này.

Bài viết này sẽ phân tích có hệ thống toàn bộ vòng đời của việc nhấn F5 (refresh thông thường), đồng thời so sánh với Ctrl+F5 (hard reload) và thao tác nhấn Enter trên thanh địa chỉ, nhằm bóc tách hành vi thực sự của trình duyệt qua các giai đoạn: cache, network, phân tích cú pháp (parsing) và render.

I. Bản chất khác biệt giữa 3 cách điều hướng (navigation)

Đầu tiên phải làm rõ: "Refresh" ≠ "Tải lại" (Reload). Trình duyệt áp dụng các chiến lược cache hoàn toàn khác nhau đối với từng thao tác của người dùng.

Thao tác của người dùng Loại hành vi Chiến lược cache Đặc điểm network request Ví dụ minh họa
F5 / Nút Refresh Refresh thông thường (Reload) Bỏ qua strong cache, kích hoạt negotiated cache (cache thương lượng) Request gửi kèm header If-Modified-Since hoặc If-None-Match "Tôi có bản nháp cũ, vui lòng xác nhận xem nó còn hiệu lực không."
Ctrl+F5 / Shift+F5 Hard Reload Bỏ qua hoàn toàn mọi loại cache Request header chứa Cache-Control: no-cache, Pragma: no-cache và không gửi header thương lượng "Bỏ qua mọi thứ tôi đang có, vui lòng cho xin bản mới nhất!"
Nhấn Enter ở thanh địa chỉ / Mở tab mới Điều hướng bình thường (Navigation) Ưu tiên dùng strong cache Nếu strong cache chưa hết hạn, sẽ không có network request nào được gửi "Tôi có sách xịn rồi, cứ thế lấy ra đọc thôi."

Lưu ý: Một số trình duyệt (như Chrome) khi mở Developer Tools (F12) sẽ mặc định chuyển hành vi của F5 thành "Disable cache". Đây là hành vi đặc thù trong chế độ debug, không thuộc tiêu chuẩn chung.

II. Khái niệm cốt lõi: Strong Cache vs Negotiated Cache

1. Strong Cache

  • Định nghĩa: Trình duyệt không cần giao tiếp với server, trả về trực tiếp tài nguyên từ cache ở local (memory cache hoặc disk cache).
  • Header điều khiển:
    • Cache-Control: max-age=3600 (HTTP/1.1, độ ưu tiên cao)
    • Expires: Wed, 26 Nov 2025 12:00:00 GMT (HTTP/1.0, dễ bị ảnh hưởng bởi sai lệch thời gian trên máy client)
  • Đặc điểm: Không có network request, thời gian phản hồi cực nhanh, nhưng có thể khiến người dùng nhìn thấy nội dung đã cũ.

2. Negotiated Cache

  • Định nghĩa: Trình duyệt gửi một "request xác thực" lên server để kiểm tra xem cache có còn hợp lệ hay không.
  • Hai cặp header kinh điển:
    1. Last-Modified / If-Modified-Since
      • Dựa trên thời gian chỉnh sửa file cuối cùng (độ chính xác ở mức giây, có thể bị đánh giá sai).
    2. ETag / If-None-Match
      • Dựa trên fingerprint (dấu vân tay) duy nhất của nội dung tài nguyên (ví dụ: mã hash). Độ chính xác cao hơn, ưu tiên cao hơn.
  • Server phản hồi:
    • Tài nguyên chưa thay đổi → Trả về 304 Not Modified (body rỗng, giúp tiết kiệm băng thông).
    • Tài nguyên đã thay đổi → Trả về 200 OK + nội dung mới + header update cache.

Chiến lược tạo ETag: Các cách implement phổ biến bao gồm mã hóa MD5 nội dung file, inode+mtime (mặc định của Nginx), hoặc custom theo business logic. ETag mang tính nhất quán mạnh giúp tránh được vấn đề vô hiệu hóa cache (cache invalidation) do "độ chính xác của timestamp không đủ".

III. Sơ đồ luồng toàn cảnh khi nhấn F5

  • Giai đoạn bắt đầu: Người dùng phát lệnh nhấn F5.
  • Giai đoạn xử lý cache: Bypass strong cache, kích hoạt quá trình network validation (xác thực mạng) của negotiated cache.
  • Server ra quyết định: Logic rẽ nhánh để kiểm tra xem tài nguyên đã thay đổi hay chưa.
  • Lấy tài nguyên: Dựa vào HTTP response 304 hoặc 200 để quyết định dùng lại cache hay tải nội dung mới.
  • Luồng render trang: Toàn bộ rendering pipeline từ bước parse HTML cho đến bước compositing (tổng hợp) cuối cùng.
  • Xử lý vòng lặp: Lặp lại quá trình xác thực cache đối với từng sub-resource.

IV. Giải thích chi tiết toàn bộ vòng đời khi refresh bằng F5

Giả sử trang hiện tại là https://example.com/index.html, người dùng nhấn F5.

Giai đoạn 1: Xác thực cache và lấy tài liệu chính (Main Document - HTML)

1. Kích hoạt lệnh refresh Trình duyệt nhận diện đây là thao tác "Reload", buộc phải bypass strong cache (bỏ qua cache mạnh), cho dù có cài đặt Cache-Control: max-age=86400 thì cũng bị vô hiệu hóa.

2. Khởi tạo request xác thực Gửi một request GET cho tài liệu HTML chính, tự động đính kèm các header thương lượng (negotiated headers) nếu trước đó đã có lưu:

3. Server ra quyết định

  • Nếu tài nguyên chưa thay đổi → Trả về 304 Not Modified, không truyền tải phần body, trình duyệt tái sử dụng (reuse) cache ở local.
  • Nếu tài nguyên đã thay đổi → Trả về 200 OK + file HTML mới + cập nhật lại ETag/Last-Modified.

Chi tiết quan trọng: Cho dù server có trả về 304, trình duyệt vẫn sẽ parse lại HTML! Bởi vì thứ được lưu trong cache chỉ là luồng byte, chứ không phải là cây DOM.

Giai đoạn 2: Parse HTML và Luồng render (Critical Rendering Path)

Cho dù HTML được lấy từ cache hay tải mới về, trình duyệt đều sẽ thực thi trọn vẹn quy trình render:

1. Dựng cây DOM

  • Parse luồng byte HTML từng dòng để tạo ra các đối tượng node.
  • Khi gặp thẻ <script>, mặc định sẽ chặn quá trình parse HTML (trừ khi có thuộc tính async hoặc defer).

2. Dựng cây CSSOM

  • Parse các inline style hoặc file CSS external (thông qua thẻ <link>).
  • CSS là tài nguyên chặn render: Không có CSSOM thì không thể dựng được Render Tree.

3. Tạo Render Tree

  • Gộp DOM và CSSOM lại, loại bỏ các node không hiển thị (ví dụ: display: none).
  • Render Tree sẽ chứa các computed style của từng node hiển thị.

4. Layout / Reflow

  • Tính toán thông tin hình học của từng node (vị trí, kích thước).
  • Điều kiện trigger: Cấu trúc DOM thay đổi, resize cửa sổ, JS đọc các thuộc tính như offset, v.v.

5. Paint / Repaint

  • Chuyển đổi Render Tree thành các pixel trên màn hình (màu sắc, viền, văn bản, v.v.).
  • Layerization : Các trình duyệt hiện đại sẽ promote các element phức tạp (như dùng transform, opacity) thành các lớp độc lập.

6. Compositing

  • Luồng tổng hợp sẽ merge các layer theo thứ tự trục Z, và cuối cùng output ra GPU để hiển thị lên màn hình.
  • Giai đoạn này có thể tạo ra các animation hiệu năng cao (ví dụ: dùng transform sẽ không trigger lại quá trình layout/paint).

Mẹo hiệu năng: Mặc dù thao tác F5 refresh có tái sử dụng một phần cache, nhưng nó vẫn phải chạy qua trọn vẹn rendering pipeline. Do đó, việc giảm độ phức tạp của DOM, tối ưu hóa CSS selector, và sử dụng hợp lý thuộc tính will-change là cực kỳ quan trọng đối với trải nghiệm refresh.

Giai đoạn 3: Xử lý cache của các sub-resource (CSS/JS/IMG)

1. Xử lý đệ quy các tài nguyên phụ thuộc Trong quá trình parse HTML, khi phát hiện các thẻ như <link>, <script>, <img>, v.v., mỗi tài nguyên này đều sẽ trigger một request negotiated cache giống hệt như cách F5 xử lý file gốc:

  • Request header cũng mang theo If-None-Match (nếu trước đó đã có ETag).
  • Server cũng sẽ trả về 304 hoặc 200.

2. Hành vi đặc biệt của JavaScript

  • Thẻ <script> truyền thống: Chặn quá trình parse HTML cho đến khi JS được tải xuống, parse và thực thi hoàn tất.
  • <script async>: Tải bất đồng bộ, tải xong sẽ thực thi ngay lập tức (điều này có thể làm lộn xộn thứ tự thực thi của các script).
  • <script defer>: Tải bất đồng bộ, nhưng trì hoãn việc thực thi cho đến tận trước khi sự kiện DOMContentLoaded fire (rất được khuyên dùng cho các file JS không quan trọng).
  • Script dạng module (type="module"): Mặc định đã mang sẵn hành vi của defer.

Xu hướng tối ưu hóa hiện đại: Việc áp dụng các kỹ thuật như rel="preload", <link rel="prefetch">, hoặc inline tài nguyên (Critical CSS/JS) có thể giúp cải thiện đáng kể tốc độ cảm nhận của người dùng sau khi nhấn F5 refresh.

V. Tổng kết so sánh: Sự khác biệt bản chất giữa F5 và các thao tác khác

Tiêu chí F5 Refresh (Refresh thông thường) Ctrl+F5 (Hard Reload) Nhấn Enter trên thanh địa chỉ
Strong Cache Bỏ qua Bỏ qua Sử dụng (Nếu còn hiệu lực)
Negotiated Cache Kích hoạt Bỏ qua Kích hoạt nếu strong cache đã hết hạn
Lượng Network Request Trung bình (Chỉ gửi request xác thực / validation) Cao (Fetch lại toàn bộ) Thấp (Có thể không có request nào)
Có parse lại HTML không? Có Có Có (Nếu hit cache thì tái sử dụng byte stream)
Ngữ cảnh sử dụng Dev debug, nội dung có thể đã được update Ép buộc lấy tài nguyên mới nhất Duyệt web hàng ngày của user

VI. Best Practices

1. Cấu hình chiến lược cache hợp lý

  • HTML: Cache-Control: no-cache (Ép buộc dùng negotiated cache, đảm bảo luôn lấy nội dung mới nhất).
  • Tài nguyên tĩnh (JS/CSS/IMG): Cache-Control: public, max-age=31536000 kết hợp với cách đặt tên file theo mã hash nội dung (ví dụ: app.a1b2c3.js), giúp đạt được mục tiêu "cache vĩnh viễn + update ngay lập tức".

2. Tận dụng ETag để tăng độ chính xác của cache

  • Tránh việc chỉ phụ thuộc vào Last-Modified, đặc biệt là trong các hệ thống CI/CD có tần suất build liên tục (thời gian sửa file thay đổi nhưng nội dung chưa chắc đã đổi).
  1. Giám sát tỉ lệ response 304
  • Tỉ lệ 304 cao cho thấy chiến lược cache đang hoạt động hiệu quả; nếu xuất hiện quá nhiều response 200, bạn cần kiểm tra xem tài nguyên có đang bị update một cách không cần thiết hay không.

4. Tránh lỗi "Nhấn F5 nhưng không update"

  • Nếu user report lỗi "đã sửa code nhưng giao diện không đổi", khả năng rất cao là file HTML đang bị dính strong cache. Bắt buộc phải đảm bảo file HTML không được set cache dài hạn.

VII. Lời kết

Thao tác nhấn F5 refresh hoàn toàn không hề đơn giản chỉ là "tải lại", nó là một sự đánh đổi cực kỳ tinh tế mà trình duyệt phải thực hiện để cân bằng giữa trải nghiệm người dùng, hiệu suất mạng và tính nhất quán của dữ liệu.

Việc hiểu rõ cơ chế caching và luồng render (rendering pipeline) nằm bên dưới không chỉ giúp chúng ta viết ra những đoạn code frontend tối ưu hơn, mà còn giúp khoanh vùng chính xác các ca bệnh kinh điển như "tại sao code mới deploy lại không nhận?".

Khi đã nắm vững những nguyên lý cốt lõi này, bạn hoàn toàn có thể bơi lội dễ dàng trong các task tối ưu hiệu năng, thiết kế cache và troubleshoot/debug, thực sự trở thành một kỹ sư frontend "không chỉ biết cách làm, mà còn hiểu thấu đáo tại sao lại làm như vậy"

Ngoài ra nếu muốn đào sâu hơn nữa, học các kiến thức chuyên sâu thực tiễn hơn từ giảng viên là chuyên gia có hơn 10 năm kinh nghiệm frontend và từng là kỹ sư tại Shopee Singapo thì bạn có thể tham khảo khoá học React Nâng Cao bên dưới của Sydexa nha!

React Nâng Cao - Chuyên Sâu với Tối Ưu Hiệu Năng
Khóa học React từ cơ bản đến nâng cao với chuyên gia. Trở thành Senior React Developer với Sydexa.
SydexaSydexa Team

Bài viết liên quan

Đừng đổ lỗi cho tối ưu hiệu năng nữa: Ứng dụng của bạn giật lag, có thể là do thiết kế sản phẩm quá tệ
Frontend
17/03/2026 · 8 phút đọc

Đừng đổ lỗi cho tối ưu hiệu năng nữa: Ứng dụng của bạn giật lag, có thể là do thiết kế sản phẩm quá tệ

Chắc hẳn mỗi khi chúng ta code xong một trang web và deploy lên production thì có một điều chúng ta khá quan tâm là Tối ưu hiệu năng (Performance Optimization). Trên mạng có nhiều bài viết chứa những thuật ngữ nghe rất đao to búa lớn: * Sử dụng Virtual List (danh sách ảo) để tối ưu việc render danh sách dài... * Sử dụng Web Worker để đẩy các tính toán phức tạp ra khỏi luồng chính (main thread)... * Sử dụng WASM để viết lại thuật toán lõi... Sau khi viết vài bài về tối ưu hiệu năng, cũng nh

Chi tiết bài viết
Server DTO: Nên giữ nguyên hay chuyển đổi?
Frontend
04/03/2026 · 12 phút đọc

Server DTO: Nên giữ nguyên hay chuyển đổi?

Trong các dự án mà Backend và Frontend được phát triển hoàn toàn tách biệt, chắc hẳn không ít lần chúng ta phải đau đầu với câu hỏi: "Dữ liệu server trả về thì nên xài luôn hay phải xào nấu lại?". Nếu dạo quanh các diễn đàn công nghệ hay đọc các bài thảo luận trên mạng, bạn sẽ thấy cuộc tranh luận về cách xử lý dữ liệu từ API này dường như chưa bao giờ có hồi kết. Cốt lõi của vấn đề luôn xoay quanh hai luồng quan điểm cực kỳ quen thuộc: "Dữ liệu backend trả về sao thì cứ tận dụng nguyên xi như

Chi tiết bài viết
Đừng lạm dụng useMemo nữa! Đây mới là Best Practice chuẩn xác dành cho bạn
Frontend
25/02/2026 · 12 phút đọc

Đừng lạm dụng useMemo nữa! Đây mới là Best Practice chuẩn xác dành cho bạn

useMemo là một React Hook giúp chúng ta ghi nhớ kết quả tính toán giữa các lần render để tối ưu hiệu năng trong một số trường hợp. Tuy nhiên, có một thực trạng đang diễn ra: người không biết thì chẳng bao giờ dùng, còn người đã biết thì lại lạm dụng nó ở mọi lúc, mọi nơi. Bài viết này sẽ giúp bạn hiểu rõ thực sự thì trong những trường hợp nào chúng ta mới nên sử dụng useMemo. Cú pháp tổng quát: useMemo hoạt động như thế nào? Ở lần render đầu tiên, useMemo sẽ thực thi hàm calculateValue (khôn

Chi tiết bài viết
Giải Thích Chi Tiết Về Các Design Patterns Front-End (Phần 1)
Frontend
18/12/2025 · 19 phút đọc

Giải Thích Chi Tiết Về Các Design Patterns Front-End (Phần 1)

Trong lập trình, các nguyên tắc SOLID là năm nguyên tắc thiết kế hướng đối tượng quan trọng, giúp nhà phát triển viết mã dễ bảo trì, mở rộng và dễ hiểu. Năm nguyên tắc này lần lượt là: * Single responsibility priciple (SRP): Một lớp chỉ nên chịu trách nhiệm về một nhiệm vụ cụ thể. * Open/Closed principle (OCP): Không được sửa đổi một class có sẵn, nhưng có thể mở rộng bằng kế thừa * Liskov substitution principe (LSP): Các đối tượng kiểu class con cần có khả năng thay thế lớp cha mà không gây

Chi tiết bài viết
Sydexa
Sydexa
SydexaSydexa

Nền tảng học lập trình với animation trực quan và bài tập tương tác, giúp bạn hiểu sâu thay vì chỉ đọc lý thuyết.

Sydexa FanpageBackend GroupFrontend Group

We learn, We share, We grow

Powered By
Cộng đồng System Design Việt Nam

contact@sydexa.com
0971489013