bfcache (phần 2): 4 thủ thuật tối ưu bfcache quan trọng

Trong phần này, chúng ta sẽ so sánh bfcache với một kỹ thuật cache phổ biến khác trong trình duyệt là HTTP Cache, phân tích các vấn đề của bfcache trong trình duyệt cũng như đưa ra giải pháp tối ưu nhất cho việc sử dụng bfcache.

Upload image

Ở phần trước, chúng ta đã tìm hiểu về bfcache - một kỹ thuật cache trong trình duyệt giúp người dùng có thể điều hướng đến các trang web đã truy cập trước đó một cách tức thời khi thực hiện các tác vụ back hay forward trên trình duyệt. bfcachecũng là một trong số các cache (bộ nhớ đệm) có sẵn trong trình duyệt, phổ biến nhất có thể kể đến đó là HTTP cache. Vậy bạn có tự hỏi rằng, cùng là cache thì liệu HTTP cache có thực hiện được những gì mà bfcache đã làm không?

Trước đó, mình cũng có nhấn mạnh rằng bfcache đã được cài sẵn vào trong các trình duyệt phổ biến hiện nay. Vậy với yếu tố luôn hiện diện trong trình duyệt thì bộ nhớ đệm này có thực sự đảm bảo rằng nó luôn mang lại trải nghiệm tốt cho người dùng không? Hay có một sự đánh đổi nào đó trong trình duyệt để được ưu tiên cho kỹ thuật bfcache này?

Trong phần này, hãy cùng mình giải đáp tất cả các vấn đề trên nhé!

Đầu tiên để có câu trả lời về HTTP Cache có thực sự làm được những gì mà bfcache làm không? Cách dễ dàng nhất đó là có sự so sánh giữa hai bộ nhớ đệm này.

So sánh bfcache với HTTP Cache

Như được biết, HTTP Cache (hay còn gọi là disk cache) là bộ nhớ đệm cho phép lưu trữ bản sao của các tài nguyên đã được tải xuống vào ổ đĩa cục bộ nhằm mục đích sử dụng lại.

Cũng giống như mọi cache khác, sử dụng HTTP Cache có thể tránh việc phải tải đi tải lại cùng một tài nguyên, các tài nguyên để tải một trang web sẽ là các file chứa toàn bộ CSS, JS cho trang đó, các hình ảnh, logo,... Và trước khi xuất hiện bfcache, việc sử dụng lại chúng từ HTTP Cache chính là một cách tối ưu đáng kể cho trình duyệt ngay cả khi việc tải lại không xảy ra tức thì giống như bfcache.

Trong khi đó, bfcache là một in-memory cache, cho phép lưu một snapshot hoàn chỉnh của một trang web. Với disk cache, nó có thể nhanh hơn trong việc tìm nạp tài nguyên từ network, nhưng với in-memory cache thì việc đọc từ đĩa lại không cần nữa mà sẽ tìm nạp toàn bộ trang từ bộ nhớ trong của trình duyệt. So sánh từ "tài nguyên" với "toàn bộ trang" cũng tạo nên sự khác biệt giữa hai bộ nhớ đệm này. Một bên thì tải từng tài nguyên để hiển thị cho toàn bộ trang và một bên là khôi phục lại trạng thái của toàn bộ trang đã được lưu hoàn toàn vào bộ nhớ trong. Rất hiếm khi tất cả các request để dùng cho việc tải lại một trang hoàn toàn được thực hiện bởi HTTP Cache. Với cách hoạt động của bfcache, việc khôi phục lại trang nhanh hơn tải lại trang là điều không cần bàn cãi.

Trên đây chính là các lý do cho thấy bfcache tối ưu hơn nhiều so với HTTP Cache trong việc điều hướng trang web. Tiếp theo, hãy cùng mình phân tích các vấn đề mà trình duyệt có thể gặp phải với bfcache cũng như cách tối ưu chúng.

Tối ưu cho bfcache trong trình duyệt

Trong thực tế, không phải tất cả các trang đều có thể lưu được trong bfcache, ngay cả khi có trang web đã lưu nhưng bfcache cũng không ở đó mãi mãi. Điều quan trọng lúc này là dev nên làm gì để cho phép trang nào là đủ hoặc không đủ cho việc lưu vào bfcache và xử lý các tác vụ quanh nó.

Để tối ưu cho bfcache, chúng ta cũng cần biết đến các sự kiện như pageshow, pagehide. Các sự kiện này cũng tương tự như các sự kiện trước đó như load, beforeunload, unload ngoại trừ chúng tương thích được với bfcache.

Sau đây, mình sẽ phân tích các vấn đề của bfcache trong trình duyệt cũng như đưa ra giải pháp cho chúng.

1. Tránh sử dụng sự kiện unload

Trong quá trình phát triển phần mềm, việc sử dụng các sự kiện như beforeunload, unload sẽ làm vô hiệu hoá bfcache trong trình duyệt. Vì vậy, dev cần thay thế bằng các giải pháp tối ưu hơn để tương thích được với bfcache. Cụ thể như:

  • Khi sử dụng sự kiện unload, bạn có thể thay thế nó bằng sự kiện tương tự là pagehide.
  • Khi sử dụng sự kiện beforeunload (hiện tại không tương thích được với trình duyệt Firefox để kích hoạt bfcache) trong một vài trường hợp cần đến sự kiện này như khi cần biết người dùng đã lưu các thay đổi hay chưa? Và xác nhận họ có muốn rời khỏi trang hay không? Bạn có thể xử lý theo cách sau:

Upload image

Rõ ràng là đừng vội mà add event này trước khi kiểm tra xem có haveChanges nào không? Với cách này, khi không có sự thay đổi nào thì ít nhiều bfcache sẽ có thể kích hoạt trong trình duyệt Firefox.

2. Giảm thiểu việc sử dụng Cache-Control: no-store

Cache-Control: no-store là một HTTP Header chỉ định cho trình duyệt không lưu các phản hồi do server trả về. Như đã so sánh với HTTP Cache, dù cùng là cache nhưng bản chất giữa chúng là khác nhau, bfcache sẽ không áp dụng HTTP Header này theo đúng đặc tính của nó. Đồng thời, bfcache cũng không lưu trữ tài nguyên của web (từ các HTTP response) để sử dụng sau này mà nó chỉ "đóng băng" trạng thái trang web trước đó vào bộ nhớ.

Trên thực tế, bfcache sẽ chỉ coi Cache-Control: no-store là một dấu hiệu để biết không lưu trang web đó vào cache. Vì chỉ coi nó là dấu hiệu cho nên nếu chúng ta lạm dụng HTTP Header cho những trường hợp không cần thiết thì sẽ vô tình khiến bfcache dễ dàng bỏ qua các trang web vốn dĩ rất cần được lưu lại. Chính vì thế, chúng ta nên cân nhắc việc sử dụng Cache-Control: no-store này cho những trường hợp cần thiết, cụ thể là những trang có thông tin cần bảo mật.

Ngược lại, dù không liên quan đến bfcache nhưng để tối ưu trong trình duyệt đối với những trang có thông tin không cần bảo mật hay nội dung cần update liên tục thì có thể sử dụng các HTTP Header như là Cache-Control: no-cache hay Cache-Control: max-age=0.

3. Cập nhật lại dữ liệu cũ hay bảo mật khi khôi phục bfcache

Một vấn đề đáng quan tâm khác khi sử dụng bfcache đó là việc caching này có thể làm lộ ra thông tin trước đó ngay cả khi người dùng đã đăng xuất. Mặc dù bạn đã đăng xuất ra khỏi trang web nhưng khi bấm quay lại thì thông tin của trang trước sẽ hiển thị ngay lập tức và coi như là bạn đã đăng nhập.

Trong trường hợp này, chắc chắn bạn cần phải xử lý để ngăn chặn việc hiển thị các thông tin bằng cách sau:

Upload image

Với đoạn snippet trên, mỗi khi khôi phục bfcache thông qua sự kiện pageshow, trình duyệt sẽ phải tải lại trang web của bạn nếu như người dùng đã đăng xuất, đồng nghĩa với việc thông tin trước đó cũng sẽ biến mất.

4. Luôn đóng các kết nối trước khi rời khỏi trang

Khi trang web được lưu trữ trong bfcache, tất cả các tác vụ JavaScript sẽ bị tạm dừng và tiếp tục ngay sau khi nó được khôi phục từ bộ nhớ đệm. Nếu các tác vụ này chỉ truy cập đến các API được tách biệt với trang hiện tại thì sẽ không có vấn đề gì.

Tuy nhiên, nếu các tác vụ này được kết nối với các API có thể truy cập đến các trang khác trong cùng một nguồn (chẳng hạn như IndexedDB, WebLocks, WebSockets,...) thì chúng có thể ngăn chặn các tác vụ đang chạy liên quan trong các tab khác. Vì vậy, bfcache đã ngăn chặn điều này bằng cách sẽ không lưu trang web vào cache trong những trường hợp trang web mở bất kỳ kết nối như IndexedDB, WebSocket, WebRTC hay có bất kỳ lệnh gọi fetch() hoặc XMLHttpRequest() nào đang diễn ra.

Và cách tốt nhất để xử lí đó là chúng ta sẽ đóng tất cả các kết nối này (nếu có) thông qua sự kiện pagehide hay freeze. Điều này sẽ cho phép trình duyệt lưu trang web vào bfcache một cách an toàn và không ảnh hưởng đến các tab liên quan khác. Sau khi trang được khôi phục thì chúng ta có thể mở lại các kết nối thông qua sự kiện pageshow hay resume.

Upload image

Một chút giải thích về các sự kiện liên quan đến bfcache và đối tượng trong callback trả về:

Upload image

Mỗi khi trang load hay unload đều sẽ liên quan đến bfcache, nơi mà trang tìm nạp từ cache hoặc lưu trữ vào cache hoặc không liên quan đến bất kỳ cache nào.

Nếu bfcache được kích hoạt thì đính kèm với các sự kiện pageshow hay pagehide sẽ nhận các đối tượng chứa thuộc tính persisted: true, còn không thì thuộc tính này sẽ là false.

Khi persisted === true:

  • Trong ngữ cảnh pageshow nghĩa là trang sẽ được phục hồi hay tìm nạp từ bfcache.
  • Trong ngữ cảnh pagehide nghĩa là trang sẽ được lưu trữ vào bfcache.

Ngược lại persisted === false nghĩa là trình duyệt sẽ load/unload bình thường và không dùng bfcache.

Sử dụng Chrome DevTools

Bên cạnh những phương pháp tối ưu cho bfcache trong trình duyệt được nêu ở trên, ta sẽ cùng tìm hiểu cách để kiểm tra một trang web có kích hoạt bfcache hay không bằng Chrome DevTool.

Đầu tiên bạn có thể vào DevTools của trình duyệt Chrome và đi đến Application > Back/forward Cache sau đó nhấn vào nút Test back/forward cache.

Nếu trang web có bfcache sẽ hiển thị thông báo như bên dưới:

Upload image

Kết

Sự khác biệt rõ ràng giữa bfcache với HTTP Cache đó là bfcache sẽ lưu trạng thái của toàn bộ trang web để khi người dùng quay lại nó sẽ khôi phục ngay lập tức, thay vì phải tải từng tài nguyên cho toàn bộ trang như HTTP Cache.

Đi cùng với lợi ích mà bfcache mang lại, các sự kiện tương thích với nó như pageshow, pagehide cũng giúp cho trình duyệt cải thiện một cách hiệu quả. Ta có thể loại bỏ một vài trường hợp không thể kích hoạt được bfcache bằng cách thay thế chúng cho các sự kiện không tương thích như unload, hay là xử lý các tác vụ đóng kết nối (như là IndexedDB, WebSocket,...) sau khi rời trang.

Như vậy, mình đã cùng các bạn tìm hiểu, phân tích và đưa ra cách khắc phục cho những vấn đề liên quan đến kỹ thuật bfcache. Hy vọng mình đã mang đến cho các bạn một vài thông tin bổ ích. Hẹn gặp lại các bạn trong bài viết tiếp theo.

Atekco - Home for Authentic Technical Consultants