Bộ nhớ đệm cho thao tác tiến/lùi

Bộ nhớ đệm cho thao tác tiến/lùi (hoặc bfcache) là một tính năng tối ưu hoá của trình duyệt, cho phép điều hướng tiến và lùi trong tích tắc. Tính năng này cải thiện đáng kể trải nghiệm duyệt web, đặc biệt là đối với những người dùng có thiết bị hoặc mạng chậm.

Là nhà phát triển web, bạn cần phải hiểu cách tối ưu hoá các trang cho bộ nhớ đệm chuyển tiếp/quay lại (bfcache) để người dùng có thể hưởng lợi.

Khả năng tương thích với trình duyệt

Tất cả các trình duyệt chính đều có bfcache, bao gồm cả Chrome từ phiên bản 96, FirefoxSafari.

Kiến thức cơ bản về bộ nhớ đệm cho thao tác tiến/lùi

Với bộ nhớ đệm cho thao tác tiến/lùi (bfcache), thay vì huỷ một trang khi người dùng di chuyển khỏi trang đó, chúng tôi sẽ hoãn huỷ và tạm dừng việc thực thi JS. Nếu người dùng nhanh chóng quay lại, chúng tôi sẽ hiển thị lại trang và tiếp tục thực thi JS. Điều này giúp người dùng chuyển trang gần như ngay lập tức.

Bạn đã bao nhiêu lần truy cập vào một trang web và nhấp vào một đường liên kết để chuyển đến một trang khác, nhưng sau đó nhận ra đó không phải là nội dung bạn muốn và nhấp vào nút quay lại? Trong thời gian chờ đợi đó, bfcache có thể tạo ra sự khác biệt lớn về tốc độ tải trang trước:

Không bật bfcache Một yêu cầu mới được bắt đầu để tải trang trước đó và tuỳ thuộc vào mức độ tối ưu hoá của trang đó cho các lượt truy cập lặp lại, trình duyệt có thể phải tải xuống lại, phân tích cú pháp lại và thực thi lại một số (hoặc tất cả) tài nguyên mà trình duyệt vừa tải xuống.
Đã bật bộ nhớ đệm cho thao tác tiến/lùi Việc tải trang trước đó gần như diễn ra ngay lập tức, vì toàn bộ trang có thể được khôi phục từ bộ nhớ mà không cần phải truy cập vào mạng.

Hãy xem video này về bộ nhớ đệm cho thao tác tiến/lùi để hiểu rõ hơn về tốc độ mà bộ nhớ đệm này có thể mang lại cho các thao tác điều hướng:

Việc sử dụng bfcache giúp các trang tải nhanh hơn nhiều trong quá trình điều hướng tiến và lùi.

Trong video, ví dụ có bfcache nhanh hơn đáng kể so với ví dụ không có bfcache.

bfcache không chỉ tăng tốc độ điều hướng mà còn giảm mức sử dụng dữ liệu, vì các tài nguyên không cần phải tải xuống lại.

Dữ liệu sử dụng Chrome cho thấy cứ 10 lượt điều hướng trên máy tính thì có 1 lượt là quay lại hoặc chuyển tiếp, còn trên thiết bị di động thì cứ 5 lượt điều hướng thì có 1 lượt là quay lại hoặc chuyển tiếp. Khi bfcache được bật, các trình duyệt có thể loại bỏ việc truyền dữ liệu và thời gian tải cho hàng tỷ trang web mỗi ngày!

Cách hoạt động của "bộ nhớ đệm"

"Bộ nhớ đệm" mà bfcache sử dụng khác với bộ nhớ đệm HTTP. Bộ nhớ đệm này đóng vai trò riêng trong việc tăng tốc các thao tác điều hướng lặp lại. bfcache là ảnh chụp nhanh của toàn bộ trang trong bộ nhớ, bao gồm cả heap JavaScript, trong khi bộ nhớ đệm HTTP chỉ chứa các phản hồi cho những yêu cầu đã thực hiện trước đó. Vì rất hiếm khi tất cả các yêu cầu cần thiết để tải một trang được thực hiện từ bộ nhớ đệm HTTP, nên các lượt truy cập lặp lại bằng cách sử dụng tính năng khôi phục bfcache luôn nhanh hơn ngay cả những thao tác điều hướng không sử dụng bfcache được tối ưu hoá tốt nhất.

Việc đóng băng một trang để có thể bật lại sau này khá phức tạp về cách bảo lưu mã đang thực hiện một cách hiệu quả nhất. Ví dụ: bạn xử lý các lệnh gọi setTimeout() như thế nào khi hết thời gian chờ trong khi trang ở trong bộ nhớ đệm chuyển tiếp/quay lại?

Câu trả lời là các trình duyệt sẽ tạm dừng mọi bộ hẹn giờ đang chờ xử lý hoặc lời hứa chưa được giải quyết cho các trang trong bộ nhớ đệm chuyển tiếp/quay lại (bfcache), bao gồm hầu hết các tác vụ đang chờ xử lý trong hàng đợi tác vụ JavaScript và tiếp tục xử lý các tác vụ nếu trang được khôi phục từ bộ nhớ đệm chuyển tiếp/quay lại.

Trong một số trường hợp, chẳng hạn như đối với thời gian chờ và lời hứa, điều này có rủi ro khá thấp, nhưng trong những trường hợp khác, điều này có thể dẫn đến hành vi khó hiểu hoặc ngoài dự kiến. Ví dụ: nếu trình duyệt tạm dừng một tác vụ bắt buộc trong giao dịch IndexedDB, thì điều này có thể ảnh hưởng đến các thẻ đang mở khác trong cùng một nguồn gốc, vì nhiều thẻ có thể truy cập đồng thời vào cùng một cơ sở dữ liệu IndexedDB. Do đó, các trình duyệt thường sẽ không cố gắng lưu vào bộ nhớ đệm các trang trong quá trình giao dịch IndexedDB hoặc trong khi sử dụng các API có thể ảnh hưởng đến các trang khác.

Để biết thêm thông tin chi tiết về cách việc sử dụng nhiều API ảnh hưởng đến điều kiện sử dụng bfcache của một trang, hãy xem bài viết Tối ưu hoá các trang cho bfcache.

Bộ nhớ đệm cho thao tác tiến/lùi và iframe

Nếu một trang có chứa iframe được nhúng, thì bản thân các iframe đó sẽ không đủ điều kiện riêng biệt để sử dụng bfcache. Ví dụ: nếu bạn chuyển đến một URL khác trong iframe, nội dung trước đó sẽ không được đưa vào bfcache và nếu bạn quay lại, trình duyệt sẽ "quay lại" trong iframe thay vì trong khung chính, nhưng thao tác quay lại trong iframe sẽ không sử dụng bfcache.

Tuy nhiên, khi khung chính được khôi phục từ bfcache, các iframe được nhúng sẽ được khôi phục như khi trang này được đưa vào bfcache.

Khung chính cũng có thể bị chặn sử dụng bfcache nếu một iframe được nhúng sử dụng các API chặn tính năng này. Bạn có thể sử dụng Chính sách về quyền được đặt trên khung chính hoặc việc sử dụng các thuộc tính sandbox để tránh trường hợp này.

Bộ nhớ đệm chuyển tiếp và quay lại (bfcache) và Ứng dụng trang đơn (SPA)

Vì bfcache hoạt động với các thao tác điều hướng do trình duyệt quản lý, nên bfcache không hoạt động đối với "thao tác điều hướng mềm" trong một ứng dụng trang đơn (SPA). Tuy nhiên, bfcache vẫn có thể giúp ích khi bạn quay lại một SPA thay vì khởi động lại hoàn toàn ứng dụng đó từ đầu.

Các API để theo dõi bfcache

Mặc dù bfcache là một tính năng tối ưu hoá mà trình duyệt tự động thực hiện, nhưng nhà phát triển vẫn cần biết thời điểm tính năng này diễn ra để có thể tối ưu hoá các trang cho tính năng nàyđiều chỉnh mọi chỉ số hoặc hoạt động đo lường hiệu suất cho phù hợp.

Các sự kiện chính được dùng để quan sát bfcache là sự kiện chuyển đổi trang pageshowpagehide, được hầu hết các trình duyệt hỗ trợ.

Các sự kiện Vòng đời trang mới hơn (freezeresume) cũng được gửi khi các trang truy cập hoặc rời khỏi bộ nhớ đệm chuyển tiếp và lùi lại, cũng như trong một số trường hợp khác, chẳng hạn như khi một thẻ nền bị đóng băng để giảm thiểu mức sử dụng CPU. Các sự kiện này chỉ được hỗ trợ trong các trình duyệt dựa trên Chromium.

Quan sát thời điểm một trang được khôi phục từ bộ nhớ đệm chuyển tiếp/quay lại

Sự kiện pageshow sẽ kích hoạt ngay sau sự kiện load khi trang tải lần đầu và bất cứ khi nào trang được khôi phục từ bộ nhớ đệm chuyển tiếp/lùi. Sự kiện pageshow có thuộc tính persisted. Thuộc tính này là true nếu trang được khôi phục từ bfcache và là false trong trường hợp khác. Bạn có thể dùng thuộc tính persisted để phân biệt các lần tải trang thông thường với các lần khôi phục bfcache. Ví dụ:

window.addEventListener('pageshow', (event) => {
  if (event.persisted) {
    console.log('This page was restored from the bfcache.');
  } else {
    console.log('This page was loaded normally.');
  }
});

Trong những trình duyệt hỗ trợ Page Lifecycle API, sự kiện resume sẽ kích hoạt khi các trang được khôi phục từ bộ nhớ đệm chuyển tiếp/lùi (ngay trước sự kiện pageshow) và khi người dùng truy cập lại vào một thẻ nền bị đóng băng. Nếu muốn cập nhật trạng thái của một trang sau khi trang đó bị đóng băng (bao gồm cả các trang trong bộ nhớ đệm chuyển tiếp/quay lại), bạn có thể sử dụng sự kiện resume. Tuy nhiên, nếu muốn đo lường tỷ lệ truy cập bộ nhớ đệm chuyển tiếp/quay lại của trang web, bạn cần sử dụng sự kiện pageshow. Trong một số trường hợp, bạn có thể cần phải sử dụng cả hai.

Để biết thông tin chi tiết về các phương pháp hay nhất để đo lường bfcache, hãy xem bài viết Cách bfcache ảnh hưởng đến hoạt động phân tích và đo lường hiệu suất.

Theo dõi thời điểm một trang đang truy cập vào bộ nhớ đệm chuyển tiếp nhanh

Sự kiện pagehide sẽ kích hoạt khi một trang huỷ tải hoặc khi trình duyệt cố gắng đưa trang đó vào bộ nhớ đệm chuyển tiếp/quay lại.

Sự kiện pagehide cũng có một thuộc tính persisted. Nếu là false, bạn có thể yên tâm rằng trang đó sắp không được đưa vào bfcache. Tuy nhiên, việc persistedtrue không đảm bảo rằng một trang sẽ được lưu vào bộ nhớ đệm. Điều này có nghĩa là trình duyệt dự định lưu trang vào bộ nhớ đệm, nhưng có thể có những yếu tố khác khiến trình duyệt không thể lưu vào bộ nhớ đệm.

window.addEventListener('pagehide', (event) => {
  if (event.persisted) {
    console.log('This page *might* be entering the bfcache.');
  } else {
    console.log('This page will unload normally and be discarded.');
  }
});

Tương tự, sự kiện freeze sẽ kích hoạt ngay sau sự kiện pagehide nếu persistedtrue, nhưng điều đó chỉ có nghĩa là trình duyệt dự định lưu trang vào bộ nhớ đệm. Tuy nhiên, có thể bạn vẫn phải loại bỏ yêu cầu đó vì một số lý do sẽ được giải thích sau.

Tối ưu hoá các trang cho bfcache

Không phải trang nào cũng được lưu trữ trong bfcache và ngay cả khi một trang được lưu trữ ở đó, trang đó cũng không lưu trữ ở đó vô thời hạn. Điều quan trọng là nhà phát triển phải hiểu rõ những yếu tố khiến các trang đủ điều kiện (và không đủ điều kiện) cho bfcache để tối đa hoá tỷ lệ truy cập vào bộ nhớ đệm.

Các phần sau đây trình bày các phương pháp hay nhất để đảm bảo trình duyệt có thể lưu trang của bạn vào bộ nhớ đệm.

Không bao giờ sử dụng sự kiện unload

Cách quan trọng nhất để tối ưu hoá cho bfcache trong tất cả các trình duyệt là không bao giờ sử dụng sự kiện unload. Ever!

Sự kiện unload gây ra vấn đề cho trình duyệt vì sự kiện này xuất hiện trước bfcache và nhiều trang trên Internet hoạt động theo giả định (hợp lý) rằng một trang sẽ không tiếp tục tồn tại sau khi sự kiện unload được kích hoạt. Điều này gây ra một thách thức vì nhiều trang trong số đó cũng được xây dựng dựa trên giả định rằng sự kiện unload sẽ kích hoạt bất cứ khi nào người dùng rời khỏi trang. Tuy nhiên, điều này không còn đúng nữa (và đã không còn đúng trong một thời gian dài).

Vì vậy, các trình duyệt phải đối mặt với một tình huống khó xử, đó là phải lựa chọn giữa một thứ có thể cải thiện trải nghiệm người dùng nhưng cũng có thể khiến trang bị lỗi.

Trên máy tính, Chrome và Firefox đã chọn không cho phép các trang sử dụng bfcache nếu các trang đó thêm một trình nghe unload. Cách này ít rủi ro hơn nhưng cũng loại bỏ rất nhiều trang. Safari sẽ cố gắng lưu vào bộ nhớ đệm một số trang có trình nghe sự kiện unload, nhưng để giảm khả năng xảy ra lỗi, trình duyệt này sẽ không chạy sự kiện unload khi người dùng chuyển sang trang khác. Điều này khiến sự kiện này trở nên rất không đáng tin cậy.

Trên thiết bị di động, Chrome và Safari sẽ cố gắng lưu vào bộ nhớ đệm các trang có trình nghe sự kiện unload vì nguy cơ xảy ra lỗi thấp hơn do sự kiện unload luôn cực kỳ không đáng tin cậy trên thiết bị di động. Firefox coi những trang sử dụng unload là không đủ điều kiện dùng bộ nhớ đệm cho thao tác tiến/lùi, ngoại trừ trên iOS. iOS yêu cầu tất cả trình duyệt phải sử dụng công cụ kết xuất WebKit, do đó, Firefox hoạt động giống như Safari.

Thay vì sử dụng sự kiện unload, hãy sử dụng sự kiện pagehide. Sự kiện pagehide sẽ kích hoạt trong mọi trường hợp mà sự kiện unload kích hoạt và cũng kích hoạt khi một trang được đưa vào bộ nhớ đệm chuyển tiếp/quay lại.

Trên thực tế, Lighthouse có một no-unload-listeners quy trình kiểm tra. Quy trình này sẽ cảnh báo cho nhà phát triển nếu có bất kỳ JavaScript nào trên trang của họ (bao gồm cả JavaScript từ các thư viện bên thứ ba) thêm một trình nghe sự kiện unload.

Do tính không đáng tin cậy và tác động đến hiệu suất của bfcache, Chrome đang tìm cách không dùng sự kiện unload nữa.

Sử dụng Chính sách về quyền để ngăn trình xử lý huỷ tải được dùng trên một trang

Những trang web không sử dụng trình xử lý sự kiện unload có thể đảm bảo rằng các trình xử lý này không được thêm bằng cách sử dụng Permissions Policy (Chính sách về quyền).

Permissions-Policy: unload=()

Điều này cũng ngăn các bên thứ ba hoặc tiện ích làm chậm trang web bằng cách thêm trình xử lý dỡ tải và khiến trang web không đủ điều kiện sử dụng bfcache.

Chỉ thêm trình nghe beforeunload có điều kiện

Sự kiện beforeunload sẽ không khiến các trang của bạn không đủ điều kiện sử dụng bfcache trong bfcache của các trình duyệt hiện đại, nhưng trước đây sự kiện này có thể khiến các trang không đủ điều kiện và vẫn không đáng tin cậy, vì vậy, hãy tránh sử dụng sự kiện này trừ phi thực sự cần thiết.

Tuy nhiên, không giống như sự kiện unload, beforeunload có những mục đích sử dụng hợp pháp. Ví dụ: khi bạn muốn cảnh báo người dùng rằng họ có những thay đổi chưa lưu và sẽ bị mất nếu rời khỏi trang. Trong trường hợp này, bạn chỉ nên thêm trình nghe beforeunload khi người dùng có các thay đổi chưa lưu và sau đó xoá ngay các trình nghe này sau khi các thay đổi chưa lưu được lưu.

Không nên
window.addEventListener('beforeunload', (event) => {
  if (pageHasUnsavedChanges()) {
    event.preventDefault();
    return event.returnValue = 'Are you sure you want to exit?';
  }
});
Mã này thêm một trình nghe beforeunload vô điều kiện.
Nên
function beforeUnloadListener(event) {
  event.preventDefault();
  return event.returnValue = 'Are you sure you want to exit?';
};

// A function that invokes a callback when the page has unsaved changes.
onPageHasUnsavedChanges(() => {
  window.addEventListener('beforeunload', beforeUnloadListener);
});

// A function that invokes a callback when the page's unsaved changes are resolved.
onAllChangesSaved(() => {
  window.removeEventListener('beforeunload', beforeUnloadListener);
});
Mã này chỉ thêm trình nghe beforeunload khi cần (và xoá trình nghe khi không cần).

Hạn chế tối đa việc sử dụng Cache-Control: no-store

Cache-Control: no-store là một tiêu đề HTTP mà máy chủ web có thể đặt trên các phản hồi để hướng dẫn trình duyệt không lưu trữ phản hồi trong bất kỳ bộ nhớ đệm HTTP nào. Được dùng cho những tài nguyên chứa thông tin nhạy cảm của người dùng, chẳng hạn như các trang sau khi đăng nhập.

Mặc dù bfcache không phải là bộ nhớ đệm HTTP, nhưng trước đây, khi Cache-Control: no-store được đặt trên chính tài nguyên trang (thay vì bất kỳ tài nguyên phụ nào), các trình duyệt đã chọn không lưu trữ trang trong bfcache, do đó, mọi trang sử dụng Cache-Control: no-store đều có thể không đủ điều kiện dùng bfcache. Chúng tôi đang nỗ lực thay đổi hành vi này cho Chrome theo cách bảo đảm quyền riêng tư.

Cache-Control: no-store hạn chế tính đủ điều kiện của một trang để lưu vào bfcache, nên bạn chỉ nên đặt tham số này trên những trang có thông tin nhạy cảm mà không bao giờ thích hợp để lưu vào bộ nhớ đệm.

Đối với những trang luôn cần phân phát nội dung mới nhất và nội dung đó không chứa thông tin nhạy cảm, hãy sử dụng Cache-Control: no-cache hoặc Cache-Control: max-age=0. Các chỉ thị này hướng dẫn trình duyệt xác thực lại nội dung trước khi phân phát và không ảnh hưởng đến điều kiện sử dụng bfcache của một trang.

Xin lưu ý rằng khi được khôi phục từ bfcache, trang sẽ được khôi phục từ bộ nhớ chứ không phải từ bộ nhớ đệm HTTP. Do đó, các chỉ thị như Cache-Control: no-cache hoặc Cache-Control: max-age=0 sẽ không được tính đến và không có hoạt động xác thực lại nào diễn ra trước khi nội dung được hiển thị cho người dùng.

Tuy nhiên, điều này vẫn có thể mang lại trải nghiệm người dùng tốt hơn, vì các lần khôi phục từ bộ nhớ đệm chuyển tiếp và quay lại diễn ra ngay lập tức và nội dung khó có khả năng bị lỗi thời vì các trang không lưu lại trong bộ nhớ đệm chuyển tiếp và quay lại quá lâu. Tuy nhiên, nếu nội dung của bạn thay đổi từng phút, bạn có thể tìm nạp mọi nội dung cập nhật bằng sự kiện pageshow, như được nêu trong phần tiếp theo.

Cập nhật dữ liệu cũ hoặc dữ liệu nhạy cảm sau khi khôi phục bfcache

Nếu trang web của bạn lưu giữ trạng thái người dùng (đặc biệt là mọi thông tin nhạy cảm của người dùng), thì dữ liệu đó cần được cập nhật hoặc xoá sau khi một trang được khôi phục từ bộ nhớ đệm chuyển tiếp/quay lại.

Ví dụ: nếu người dùng chuyển đến trang thanh toán rồi cập nhật giỏ hàng, thì thao tác điều hướng quay lại có thể hiển thị thông tin đã lỗi thời nếu một trang cũ được khôi phục từ bộ nhớ đệm chuyển tiếp/quay lại.

Một ví dụ khác quan trọng hơn là nếu người dùng đăng xuất khỏi một trang web trên máy tính công cộng và người dùng tiếp theo nhấp vào nút quay lại. Điều này có thể làm lộ dữ liệu riêng tư mà người dùng cho rằng đã bị xoá khi họ đăng xuất.

Để tránh những trường hợp như thế này, bạn nên luôn cập nhật trang sau sự kiện pageshow nếu event.persistedtrue:

window.addEventListener('pageshow', (event) => {
  if (event.persisted) {
    // Do any checks and updates to the page
  }
});

Mặc dù tốt nhất là bạn nên cập nhật nội dung tại chỗ, nhưng đối với một số thay đổi, bạn có thể muốn buộc tải lại toàn bộ. Đoạn mã sau đây kiểm tra sự hiện diện của một cookie dành riêng cho trang web trong sự kiện pageshow và tải lại nếu không tìm thấy cookie:

window.addEventListener('pageshow', (event) => {
  if (event.persisted && !document.cookie.match(/my-cookie)) {
    // Force a reload if the user has logged out.
    location.reload();
  }
});

Việc tải lại có ưu điểm là vẫn giữ được nhật ký (để cho phép chuyển tiếp), nhưng việc chuyển hướng có thể phù hợp hơn trong một số trường hợp.

Quảng cáo và khôi phục bfcache

Bạn có thể muốn tránh sử dụng bộ nhớ đệm chuyển tiếp và quay lại để phân phát một nhóm quảng cáo mới trên mỗi lần điều hướng quay lại/chuyển tiếp. Tuy nhiên, ngoài việc ảnh hưởng đến hiệu suất, chúng ta cũng không chắc chắn liệu hành vi này có giúp tăng mức độ tương tác với quảng cáo hay không. Người dùng có thể đã nhận thấy một quảng cáo mà họ dự định quay lại nhấp vào, nhưng khi tải lại thay vì khôi phục từ bộ nhớ đệm chuyển tiếp/lùi, họ sẽ không thể nhấp vào quảng cáo đó. Bạn nên kiểm thử trường hợp này (tốt nhất là bằng thử nghiệm A/B) trước khi đưa ra giả định.

Đối với những trang web muốn làm mới quảng cáo khi khôi phục bfcache, thì việc chỉ làm mới quảng cáo trên sự kiện pageshow khi event.persistedtrue sẽ cho phép điều này xảy ra mà không ảnh hưởng đến hiệu suất trang. Hãy liên hệ với nhà cung cấp quảng cáo của bạn, nhưng đây là một ví dụ về cách thực hiện việc này bằng Thẻ nhà xuất bản của Google.

Tránh sử dụng window.opener tham chiếu

Trong các trình duyệt cũ, nếu một trang được mở bằng window.open() từ một đường liên kết có target=_blank mà không chỉ định rel="noopener", thì trang mở sẽ có một tham chiếu đến đối tượng cửa sổ của trang đã mở.

Ngoài việc gây ra rủi ro bảo mật, một trang có giá trị tham chiếu window.opener khác rỗng không thể được đưa vào bộ nhớ đệm chuyển tiếp và quay lại một cách an toàn, vì điều đó có thể làm hỏng mọi trang đang cố gắng truy cập vào trang đó.

Do đó, tốt nhất là bạn nên tránh tạo các tham chiếu window.opener. Bạn có thể thực hiện việc này bằng cách sử dụng rel="noopener" bất cứ khi nào có thể (lưu ý rằng đây hiện là chế độ mặc định trong tất cả các trình duyệt hiện đại). Nếu trang web của bạn yêu cầu mở một cửa sổ và kiểm soát cửa sổ đó thông qua window.postMessage() hoặc trực tiếp tham chiếu đến đối tượng cửa sổ, thì cả cửa sổ đã mở và cửa sổ mở đều sẽ không đủ điều kiện sử dụng bfcache.

Đóng các kết nối đang mở trước khi người dùng chuyển sang trang khác

Như đã đề cập trước đó, khi một trang được lưu giữ trong bộ nhớ đệm cho thao tác tiến/lùi, trang đó sẽ tạm dừng tất cả các tác vụ JavaScript đã lên lịch và tiếp tục các tác vụ đó khi trang được lấy ra khỏi bộ nhớ đệm.

Nếu các tác vụ JavaScript theo lịch này chỉ truy cập vào các API DOM (hoặc các API khác chỉ dành riêng cho trang hiện tại), thì việc tạm dừng các tác vụ này trong khi người dùng không nhìn thấy trang sẽ không gây ra bất kỳ vấn đề nào.

Tuy nhiên, nếu các tác vụ này được kết nối với các API cũng có thể truy cập từ các trang khác trong cùng một nguồn gốc (ví dụ: IndexedDB, Web Locks, WebSockets), thì điều này có thể gây ra vấn đề vì việc tạm dừng các tác vụ này có thể ngăn mã trong các thẻ khác chạy.

Do đó, một số trình duyệt sẽ không cố gắng đưa một trang vào bộ nhớ đệm chuyển tiếp/quay lại trong các trường hợp sau:

Nếu trang của bạn đang sử dụng bất kỳ API nào trong số này, bạn nên đóng các kết nối và xoá hoặc ngắt kết nối các đối tượng theo dõi trong sự kiện pagehide hoặc freeze. Điều này cho phép trình duyệt lưu trang vào bộ nhớ đệm một cách an toàn mà không ảnh hưởng đến các thẻ đang mở khác.

Sau đó, nếu trang được khôi phục từ bộ nhớ đệm chuyển tiếp/quay lại, bạn có thể mở lại hoặc kết nối lại với các API đó trong sự kiện pageshow hoặc resume.

Ví dụ sau đây cho thấy cách đảm bảo rằng các trang sử dụng IndexedDB đủ điều kiện sử dụng bfcache bằng cách đóng một kết nối đang mở trong trình nghe sự kiện pagehide:

let dbPromise;
function openDB() {
  if (!dbPromise) {
    dbPromise = new Promise((resolve, reject) => {
      const req = indexedDB.open('my-db', 1);
      req.onupgradeneeded = () => req.result.createObjectStore('keyval');
      req.onerror = () => reject(req.error);
      req.onsuccess = () => resolve(req.result);
    });
  }
  return dbPromise;
}

// Close the connection to the database when the user leaves.
window.addEventListener('pagehide', () => {
  if (dbPromise) {
    dbPromise.then(db => db.close());
    dbPromise = null;
  }
});

// Open the connection when the page is loaded or restored from bfcache.
window.addEventListener('pageshow', () => openDB());

Kiểm tra để đảm bảo các trang của bạn có thể lưu vào bộ nhớ đệm

Chrome DevTools có thể giúp bạn kiểm thử các trang để đảm bảo rằng các trang đó được tối ưu hoá cho bfcache và xác định mọi vấn đề có thể khiến các trang đó không đủ điều kiện.

Cách kiểm tra một trang:

  1. Chuyển đến trang đó trong Chrome.
  2. Trong Công cụ cho nhà phát triển, hãy chuyển đến Ứng dụng -> Bộ nhớ đệm đi và về.
  3. Nhấp vào nút Run Test (Chạy kiểm thử). Sau đó, Công cụ cho nhà phát triển sẽ cố gắng chuyển hướng ra khỏi và quay lại để xác định xem trang có thể được khôi phục từ bộ nhớ đệm chuyển tiếp/quay lại hay không.
Bảng điều khiển bộ nhớ đệm cho thao tác tiến/lùi trong Công cụ cho nhà phát triển
Bảng điều khiển Bộ nhớ đệm đi tới và quay lại trong Công cụ cho nhà phát triển.

Nếu kiểm thử thành công, bảng điều khiển sẽ báo cáo "Đã khôi phục từ bộ nhớ đệm cho thao tác tiến/lùi".

Công cụ cho nhà phát triển báo cáo rằng một trang đã được khôi phục thành công từ bộ nhớ đệm chuyển tiếp nhanh
Một trang đã được khôi phục thành công.

Nếu không thành công, bảng điều khiển sẽ cho biết lý do. Nếu lý do là điều mà bạn có thể giải quyết với tư cách là nhà phát triển, thì bảng điều khiển sẽ đánh dấu lý do đó là Có thể thực hiện.

Công cụ cho nhà phát triển báo cáo lỗi khi khôi phục trang từ bộ nhớ đệm cho thao tác tiến/lùi
Một thử nghiệm bfcache không thành công với kết quả có thể hành động.

Trong ví dụ này, việc sử dụng trình nghe sự kiện unload khiến trang không đủ điều kiện dùng bộ nhớ đệm cho thao tác tiến/lùi. Bạn có thể khắc phục bằng cách chuyển từ unload sang sử dụng pagehide:

Nên
window.addEventListener('pagehide', ...);
Không nên
window.addEventListener('unload', ...);

Lighthouse 10.0 cũng thêm một bài kiểm tra bfcache, thực hiện một bài kiểm tra tương tự. Để biết thêm thông tin, hãy xem tài liệu về quy trình kiểm tra bfcache.

Cách bfcache ảnh hưởng đến hoạt động phân tích và đo lường hiệu suất

Nếu sử dụng một công cụ phân tích để đo lường số lượt truy cập vào trang web của mình, bạn có thể nhận thấy tổng số lượt xem trang được báo cáo giảm xuống khi Chrome bật bfcache cho nhiều người dùng hơn.

Trên thực tế, có thể bạn đang báo cáo thiếu số lượt xem trang từ các trình duyệt khác triển khai bfcache, vì nhiều thư viện phân tích phổ biến không đo lường các lượt khôi phục bfcache dưới dạng lượt xem trang mới.

Để tính cả các lượt khôi phục bfcache vào số lượt xem trang, hãy đặt trình nghe cho sự kiện pageshow và kiểm tra thuộc tính persisted.

Ví dụ sau đây cho thấy cách thực hiện việc này bằng Google Analytics. Các công cụ phân tích khác có thể sử dụng logic tương tự:

// Send a pageview when the page is first loaded.
gtag('event', 'page_view');

window.addEventListener('pageshow', (event) => {
  // Send another pageview if the page is restored from bfcache.
  if (event.persisted) {
    gtag('event', 'page_view');
  }
});

Đo lường tỷ lệ truy cập vào bộ nhớ đệm chuyển tiếp/quay lại

Bạn cũng có thể đo lường xem bộ nhớ đệm cho thao tác tiến/lùi có được sử dụng hay không để xác định những trang không sử dụng bộ nhớ đệm này. Bạn có thể thực hiện việc này bằng cách đo lường loại điều hướng cho lượt tải trang:

// Send a navigation_type when the page is first loaded.
gtag('event', 'page_view', {
   'navigation_type': performance.getEntriesByType('navigation')[0].type;
});

window.addEventListener('pageshow', (event) => {
  if (event.persisted) {
    // Send another pageview if the page is restored from bfcache.
    gtag('event', 'page_view', {
      'navigation_type': 'back_forward_cache';
    });
  }
});

Tính tỷ lệ truy cập bfcache bằng cách sử dụng số lượt điều hướng back_forward và số lượt điều hướng back_forward_cache.

Bạn cần lưu ý rằng có một số trường hợp ngoài tầm kiểm soát của chủ sở hữu trang web mà thao tác điều hướng Quay lại/Tiến sẽ không sử dụng bộ nhớ đệm chuyển tiếp/quay lại, bao gồm:

  • khi người dùng thoát trình duyệt rồi khởi động lại
  • khi người dùng sao chép một thẻ
  • khi người dùng đóng một thẻ rồi mở lại

Trong một số trường hợp, một số trình duyệt có thể giữ lại loại thao tác điều hướng ban đầu và do đó có thể hiển thị một loại back_forward mặc dù đây không phải là thao tác điều hướng Quay lại/Tiến.

Ngay cả khi không có các loại trừ đó, bfcache sẽ bị loại bỏ sau một khoảng thời gian để tiết kiệm bộ nhớ.

Vì vậy, chủ sở hữu trang web không nên mong đợi tỷ lệ truy cập vào bộ nhớ đệm trang sau là 100% cho tất cả các thao tác điều hướng back_forward. Tuy nhiên, việc đo lường tỷ lệ này có thể hữu ích để xác định những trang mà bản thân trang đó đang ngăn việc sử dụng bfcache cho một tỷ lệ lớn các thao tác điều hướng về trước và về sau.

Nhóm Chrome đã thêm API NotRestoredReasons để giúp hiển thị lý do khiến các trang không sử dụng bộ nhớ đệm chuyển tiếp và quay lại, nhờ đó nhà phát triển có thể cải thiện tỷ lệ truy cập bộ nhớ đệm chuyển tiếp và quay lại. Nhóm Chrome cũng đã thêm các loại thao tác điều hướng vào CrUX, nhờ đó bạn có thể xem số lượng thao tác điều hướng bfcache ngay cả khi không tự đo lường.

Đo lường hiệu suất

bfcache cũng có thể ảnh hưởng tiêu cực đến các chỉ số hiệu suất được thu thập trong thực tế, cụ thể là những chỉ số đo lường thời gian tải trang.

Vì các thao tác điều hướng bfcache khôi phục một trang hiện có thay vì bắt đầu tải một trang mới, nên tổng số lượt tải trang được thu thập sẽ giảm khi bfcache được bật. Tuy nhiên, điều quan trọng là những lần tải trang được thay thế bằng các lần khôi phục từ bộ nhớ đệm chuyển tiếp/lùi có thể là một số lần tải trang nhanh nhất trong tập dữ liệu của bạn. Điều này là do theo định nghĩa, thao tác tiến và lùi là lượt truy cập lặp lại và các lượt tải trang lặp lại thường nhanh hơn so với lượt tải trang của khách truy cập lần đầu (do tính năng lưu vào bộ nhớ đệm HTTP, như đã đề cập trước đó).

Kết quả là có ít lượt tải trang nhanh hơn trong tập dữ liệu của bạn, điều này có thể làm sai lệch phân phối chậm hơn – mặc dù hiệu suất mà người dùng trải nghiệm có thể đã được cải thiện!

Có một số cách để giải quyết vấn đề này. Một cách là chú thích tất cả các chỉ số tải trang bằng loại điều hướng tương ứng: navigate, reload, back_forward hoặc prerender. Nhờ đó, bạn có thể tiếp tục theo dõi hiệu suất của mình trong các loại điều hướng này, ngay cả khi mức phân phối tổng thể bị lệch theo hướng tiêu cực. Bạn nên sử dụng phương pháp này cho các chỉ số tải trang không tập trung vào người dùng, chẳng hạn như Thời gian đến byte đầu tiên (TTFB).

Đối với các chỉ số tập trung vào người dùng như Chỉ số quan trọng chính của trang web, lựa chọn tốt hơn là báo cáo một giá trị thể hiện chính xác hơn trải nghiệm của người dùng.

Tác động đến Các chỉ số quan trọng chính của trang web

Các chỉ số quan trọng chính của trang web đo lường trải nghiệm của người dùng về một trang web trên nhiều phương diện (tốc độ tải, khả năng tương tác, độ ổn định của hình ảnh). Vì người dùng trải nghiệm tính năng khôi phục từ bộ nhớ đệm chuyển tiếp và bộ nhớ đệm sau (bfcache) dưới dạng các thao tác điều hướng nhanh hơn so với tải toàn bộ trang, nên các chỉ số quan trọng chính của trang web cần phản ánh điều này. Sau tất cả, người dùng không quan tâm đến việc bfcache có được bật hay không, họ chỉ quan tâm đến việc điều hướng có nhanh hay không!

Các công cụ thu thập và báo cáo về các chỉ số Core Web Vitals, chẳng hạn như Báo cáo trải nghiệm người dùng của Chrome, coi các lần khôi phục bfcache là các lượt truy cập trang riêng biệt trong tập dữ liệu của chúng. Mặc dù không có API hiệu suất web chuyên dụng để đo lường các chỉ số này sau khi khôi phục bfcache, nhưng bạn có thể ước chừng các giá trị của chúng bằng cách sử dụng các API web hiện có:

Để biết thêm thông tin về cách bfcache ảnh hưởng đến từng chỉ số, hãy xem các trang hướng dẫn về từng chỉ số Core Web Vitals. Để xem ví dụ cụ thể về cách triển khai các phiên bản bfcache của những chỉ số này, hãy tham khảo PR thêm các chỉ số đó vào thư viện web-vitals JS.

Thư viện JavaScript web-vitals hỗ trợ việc khôi phục bfcache trong các chỉ số mà thư viện này báo cáo.

Tài nguyên khác