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. Cải thiện đáng kể trải nghiệm duyệt web, đặc biệt là đối với người dùng có mạng hoặc thiết bị chậm hơn.
Là nhà phát triển web, bạn cần hiểu cách tối ưu hoá các trang của bạn để dùng bfcache, nhờ đó 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ả trình duyệt chính đều có bfcache, bao gồm cả Chrome kể từ phiên bản 96, Firefox và Safari.
Kiến thức cơ bản về bfcache
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 rời khỏi trang, chúng ta sẽ hoãn việc huỷ và tạm dừng việc thực thi JS. Nếu người dùng sớm quay lại, chúng ta sẽ cho trang hiển thị lại và huỷ tạm dừng thực thi JS. Nhờ đó, người dùng có thể điều hướng trang gần như ngay lập tức.
Bạn đã truy cập vào một trang web bao nhiêu lần và nhấp vào đường liên kết để chuyển đến một trang khác, nhưng rồi bạn nhận ra đó không phải là trang web mình muốn rồi nhấp vào nút quay lại? Tại thời điểm đó, 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ại, trình duyệt có thể phải tải xuống, 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 vừa tải xuống. |
Khi bfcache được bật | Việc tải trang trước về cơ bản là tức thì, 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ề cách hoạt động của bfcache để hiểu được tốc độ mà tính năng này có thể mang lại cho các thao tác điều hướng:
Trong video, ví dụ có bfcache nhanh hơn khá nhiều 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ì không cần phải tải xuống lại tài nguyên.
Dữ liệu về mức sử dụng Chrome cho thấy 1 trong 10 thao tác điều hướng trên máy tính và 1 trong 5 thao tác điều hướng trên thiết bị di động là thao tác quay lại hoặc chuyển tiếp. Khi bật bfcache, 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à bản tổng quan nhanh về toàn bộ trang trong bộ nhớ, bao gồm cả vùng nhớ khối xếp JavaScript, trong khi bộ nhớ đệm HTTP chỉ chứa các phản hồi cho các 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ại bằng cách khôi phục bfcache luôn nhanh hơn ngay cả các thao tác điều hướng không phải bfcache được tối ưu hoá tốt nhất.
Việc cố định một trang để có thể bật lại sau này có liên quan đến một số độ phức tạp về cách tốt nhất để lưu giữ mã đang tiến hành. Ví dụ: bạn xử lý các lệnh gọi setTimeout()
khi hết thời gian chờ trong khi trang đang ở bfcache như thế nào?
Câu trả lời là trình duyệt 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 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ừ bfcache.
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 các trường hợp khác, điều này có thể dẫn đến hành vi khó hiểu hoặc không mong muốn. Ví dụ: nếu trình duyệt tạm dừng một tác vụ bắt buộc trong một 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 vào cùng một cơ sở dữ liệu IndexedDB cùng một lúc. Do đó, trình duyệt thường sẽ không cố gắng lưu các trang vào bộ nhớ đệm trong khi giao dịch IndexedDB đang diễn ra 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ề ảnh hưởng của nhiều cách sử dụng API đối với khả năng sử dụng bfcache của một trang, hãy xem bài viết Tối ưu hoá trang cho bfcache.
bfcache và iframe
Nếu một trang chứa các iframe được nhúng thì chính các iframe đó không đủ điều kiện cho bfcache. Ví dụ: nếu bạn chuyển đến một trang khác trong iframe, nhưng sau đó 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.
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 việc này. Bạn có thể sử dụng Chính sách quyền được đặt trên khung chính hoặc sử dụng các thuộc tính sandbox
để tránh điều này.
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 tính năng này không hoạt động với "các 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ể hữu ích khi quay lại SPA thay vì khởi tạo lại toàn bộ ứng dụng đó từ đầu.
Các API để quan sát bfcache
Mặc dù bfcache là một tính năng tối ưu hoá do trình duyệt thực hiện tự động, nhưng nhà phát triển vẫn cần phải biết thời điểm xảy ra việc đó để có thể tối ưu hoá trang cũng như điều chỉnh mọi chỉ số hoặc phương pháp đo lường hiệu suất cho phù hợp.
Các sự kiện chính dùng để quan sát bfcache là sự kiện chuyển đổi trang pageshow
và pagehide
, được hầu hết các trình duyệt hỗ trợ.
Các sự kiện mới hơn trong Vòng đời trang – freeze
và resume
– cũng được gửi đi khi các trang truy cập hoặc rời khỏi bfcache, cũng như trong một số trường hợp khác, chẳng hạn như khi một thẻ trong nền bị treo để giảm thiểu mức sử dụng CPU. Những 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ừ bfcache
Sự kiện pageshow
kích hoạt ngay sau sự kiện load
khi trang đang tải lần đầu và bất cứ khi nào trang được khôi phục từ bfcache. Sự kiện pageshow
có thuộc tính persisted
, là true
nếu trang được khôi phục từ bfcache và false
nếu không. Bạn có thể sử dụng thuộc tính persisted
để phân biệt các lượt tải trang thông thường với các lượt 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 các trình duyệt hỗ trợ API Vòng đời trang, sự kiện resume
sẽ kích hoạt khi các trang được khôi phục từ bfcache (ngay trước sự kiện pageshow
) và khi người dùng truy cập lại 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 bfcache), 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 vào bộ nhớ đệm bfcache 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 Tác động của bfcache đối với số liệu phân tích và đo lường hiệu suất.
Quan sát thời điểm một trang đang chuyển vào bfcache
Sự kiện pagehide
kích hoạt khi một trang bị huỷ tải hoặc khi trình duyệt cố gắng đưa trang đó vào bfcache.
Sự kiện pagehide
cũng có một thuộc tính persisted
. Nếu giá trị này là false
, bạn có thể chắc chắn rằng trang đó sẽ không sắp chuyển vào bfcache. Tuy nhiên, việc persisted
là true
không đảm bảo rằng trang sẽ được lưu vào bộ nhớ đệm. Tức là trình duyệt có ý định lưu trang vào bộ nhớ đệm, nhưng có thể có các yếu tố khác khiến trình duyệt không thể lưu trang 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 persisted
là true
, nhưng điều đó chỉ có nghĩa là trình duyệt dự định lưu trang vào bộ nhớ đệm. Có thể bạn vẫn phải loại bỏ mã này vì một số lý do được giải thích sau.
Tối ưu hoá các trang của bạn 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 đó sẽ không lưu trữ vô thời hạn. Nhà phát triển cần hiểu rõ những yếu tố khiến trang đủ điều kiện (và không đủ điều kiện) sử dụng 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 những phương pháp hay nhất để trình duyệt có thể lưu vào bộ nhớ đệm các trang của bạn càng nhiều càng tốt.
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ả trình duyệt là không bao giờ sử dụng sự kiện unload
. Không bao giờ!
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 với 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. Điều này không còn đúng nữa (và đã không còn đúng từ lâu).
Vì vậy, trình duyệt phải đối mặt với một tình huống khó xử, họ phải chọn giữa một tính năng có thể cải thiện trải nghiệm người dùng nhưng cũng có thể gây ra nguy cơ làm hỏng trang.
Trên máy tính, Chrome và Firefox đã chọn để các trang không đủ điều kiện dùng bộ nhớ đệm bfcache nếu thêm trình nghe unload
. Phương pháp 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 một số trang vào bộ nhớ đệm bằng trình nghe sự kiện unload
, nhưng để giảm khả năng bị hỏng, trình duyệt này sẽ không chạy sự kiện unload
khi người dùng rời khỏi trang, khiến sự kiện này rất không đáng tin cậy.
Trên thiết bị di động, Chrome và Safari sẽ cố gắng lưu các trang vào bộ nhớ đệm bằng trình nghe sự kiện unload
vì nguy cơ bị hỏng 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 các trang sử dụng unload
là không đủ điều kiện sử dụng bfcache, 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 sẽ 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 sự kiện unload
kích hoạt và cũng kích hoạt khi một trang được đưa vào bfcache.
Trên thực tế, Lighthouse có một tính năng kiểm tra no-unload-listeners
. Tính năng này sẽ cảnh báo 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ừ thư viện của bên thứ ba) thêm trình nghe sự kiện unload
.
Do không đáng tin cậy và ảnh hưởng đến hiệu suất của bfcache, Chrome đang tìm cách ngừng sử dụng sự kiện unload
.
Sử dụng Chính sách quyền để ngăn trình xử lý huỷ tải được sử dụng trên một trang
Các trang web không sử dụng trình xử lý sự kiện unload
có thể đảm bảo không thêm các trình xử lý này bằng cách sử dụng Chính sách quyền.
Permission-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ý giải phóng và khiến trang web không đủ điều kiện sử dụng bfcache.
Chỉ thêm trình nghe beforeunload
theo đ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 các trình duyệt hiện đại, nhưng trước đây sự kiện này đã 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ó các trường hợp sử dụng hợp lệ. Ví dụ: khi bạn muốn cảnh báo người dùng rằng họ có các thay đổi chưa được lưu, họ sẽ 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, sau đó xoá các trình nghe đó ngay sau khi lưu các thay đổi chưa lưu.
window.addEventListener('beforeunload', (event) => { if (pageHasUnsavedChanges()) { event.preventDefault(); return event.returnValue = 'Are you sure you want to exit?'; } });
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); });
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. Thuộc tính này được dùng cho các 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 (chứ không phải bất kỳ tài nguyên phụ nào), trình duyệt đã chọn không lưu trữ trang trong bfcache, vì vậy, mọi trang sử dụng Cache-Control: no-store
có thể không đủ điều kiện sử dụng bfcache. Chúng tôi đang tiến hành thay đổi hành vi này cho Chrome theo cách bảo đảm quyền riêng tư.
Vì Cache-Control: no-store
hạn chế điều kiện của một trang để sử dụng bfcache, nên bạn chỉ nên đặt thuộc tính này trên các trang chứa 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 cần luô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
. Những lệnh 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à các lệnh này không ảnh hưởng đến điều kiện dùng bộ nhớ đệm của trang web.
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 lệnh như Cache-Control: no-cache
hoặc Cache-Control: max-age=0
sẽ không được tính đến và không có quá trình xác thực lại nào xảy ra trước khi nội dung hiển thị cho người dùng.
Tuy nhiên, đây vẫn có thể là trải nghiệm người dùng tốt hơn vì quá trình khôi phục bfcache diễn ra tức thì và vì các trang không lưu lại trong bfcache quá lâu nên nội dung có thể không bị lỗi thời. Tuy nhiên, nếu nội dung của bạn thay đổi từng phút, thì bạn có thể tìm nạp mọi nội dung cập nhật bằng sự kiện pageshow
, như trình bày trong phần tiếp theo.
Cập nhật dữ liệu cũ hoặc 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 trang được khôi phục từ bfcache.
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 quay lại có thể hiển thị thông tin đã lỗi thời nếu trang cũ được khôi phục từ bfcache.
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ư vậy, bạn nên luôn cập nhật trang sau một sự kiện pageshow
nếu event.persisted
là true
:
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ộ. Mã sau đây kiểm tra xem có cookie dành riêng cho trang web trong sự kiện pageshow
hay không 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();
}
});
Lợi thế của việc tải lại là sẽ vẫn bảo toàn được lịch sử (để cho phép điều hướng chuyển tiếp), nhưng chuyển hướng có thể thích hợp hơn trong một số trường hợp.
Khôi phục quảng cáo và bfcache
Bạn có thể muốn tránh sử dụng bfcache để phân phát một nhóm quảng cáo mới trên mỗi thao tác điều hướng lui/tiến. Tuy nhiên, ngoài việc tác động đến hiệu suất, hành vi này có dẫn đến mức độ tương tác tốt hơn với quảng cáo hay không vẫn còn là câu hỏi. 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 nhưng bằng cách tải lại thay vì khôi phục từ bfcache, họ không thể thực hiện được. Việc thử nghiệm tình huống này (tốt nhất là bằng thử nghiệm A/B) là rất quan trọng 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 bộ nhớ đệm, thì chỉ làm mới quảng cáo trên sự kiện pageshow
khi event.persisted
là true
cho phép việc này xảy ra mà không ảnh hưởng đến hiệu suất của trang. Hãy liên hệ với nhà cung cấp quảng cáo của bạn, nhưng dưới đâ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 tham chiếu window.opener
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 đang mở sẽ có tham chiếu đến đối tượng cửa sổ của trang đã mở.
Ngoài việc gây rủi ro bảo mật, một trang có tham chiếu window.opener
khác rỗng không thể được đưa vào bfcache một cách an toàn, vì điều đó có thể làm hỏng mọi trang cố gắng truy cập vào trang đó.
Do đó, tốt nhất bạn nên tránh tạo tệp 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à giá trị mặc định trong tất cả trình duyệt hiện đại). Nếu trang web của bạn yêu cầu phải mở một cửa sổ và kiểm soát cửa sổ đó thông qua window.postMessage()
hoặc tham chiếu trực tiếp đến đối tượng cửa sổ, thì cả cửa sổ đang mở và trình mở đều không đủ điều kiện để dùng bfcache.
Đóng các kết nối đang mở trước khi người dùng rời khỏi
Như đã đề cập trước đó, khi một trang được lưu giữ trong bfcache, trang đó sẽ tạm dừng tất 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 được lên 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 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 mà cũng có thể truy cập được từ các trang khác có cùng nguồn gốc (ví dụ: IndexedDB, Web Locks, WebSockets), thì việc này có thể gây ra sự cố 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 tìm cách đặt một trang vào bfcache trong các trường hợp sau:
- Các trang có kết nối IndexedDB đang mở
- Các trang có fetch() hoặc XMLHttpRequest đang tiến hành
- Các trang có kết nối WebSocket hoặc WebRTC đang mở
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 trình quan sát trong sự kiện pagehide
hoặc freeze
. Điều đó 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ừ bfcache, 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 thử để đảm bảo các trang của bạn có thể lưu vào bộ nhớ đệm
Công cụ dành cho nhà phát triển của Chrome có thể giúp bạn kiểm tra các trang của mình để đả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:
- Chuyển đến trang đó trong Chrome.
- Trong DevTools, hãy chuyển đến Application (Ứng dụng) -> Back-forward Cache (Bộ nhớ đệm lui-tiến).
- Nhấp vào nút Run Test (Chạy kiểm thử). Sau đó, DevTools sẽ cố gắng rời khỏi và quay lại để xác định xem có thể khôi phục trang từ bfcache hay không.
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".
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ể 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 để sử dụng bfcache. Bạn có thể khắc phục vấn đề đó bằng cách chuyển từ unload
sang sử dụng pagehide
:
window.addEventListener('pagehide', ...);
window.addEventListener('unload', ...);
Lighthouse 10.0 cũng thêm một quy trình kiểm tra bfcache, thực hiện một bài kiểm thử 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.
Mức độ ảnh hưởng của bfcache đến số liệu 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 đã báo cáo thiếu lượt xem trang từ các trình duyệt khác có triển khai bfcache, vì nhiều thư viện phân tích phổ biến không đo lường số lượt khôi phục bfcache dưới dạng lượt xem trang mới.
Để đưa 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 cho thấy cách làm việc này với 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 bfcache
Bạn cũng nên đo lường xem bfcache có được sử dụng hay không để giúp xác định những trang không sử dụng bfcache. 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 nằm ngoài tầm kiểm soát của chủ sở hữu trang web, khi thao tác Quay lại/Tiến sẽ không sử dụng bfcache, bao gồm:
- khi người dùng thoát trình duyệt và khởi động lại trình duyệt
- 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 thẻ đó
Trong một số trường hợp như vậy, 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 trường hợp ngoại lệ đó, bfcache sẽ bị loại bỏ sau một khoảng thời gian để tiết kiệm bộ nhớ.
Do đó, chủ sở hữu trang web không nên kỳ vọng tỷ lệ truy cập vào bộ nhớ đệm bfcache đạt 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à chính trang đó đang ngăn việc sử dụng bfcache cho một tỷ lệ cao các thao tác điều hướng quay lại và chuyển tiếp.
Nhóm Chrome đã thêm NotRestoredReasons
API để giúp nêu ra lý do các trang không sử dụng bfcache, nhờ đó nhà phát triển có thể cải thiện tỷ lệ truy cập bfcache. Nhóm Chrome cũng đã thêm các loại điều hướng vào CrUX để có thể xem số lượt đ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 trực tiếp, cụ thể là các 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 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à việc tải trang được thay thế bằng việc khôi phục bfcache có thể là một trong những lượt tải trang nhanh nhất trong tập dữ liệu của bạn. Lý do là theo định nghĩa, thao tác quay lại và chuyển tiếp là các lượt truy cập lại và lượt tải trang lại thường nhanh hơn lượt tải trang của khách truy cập lần đầu (do lưu vào bộ nhớ đệm HTTP, như đã đề cập trước đó).
Kết quả là giảm tốc độ tải trang trong tập dữ liệu, do đó có thể làm lệch tốc độ phân phối chậm hơn, mặc dù thực tế là hiệu suất mà người dùng trải nghiệm có thể đã cải thiện!
Có một số cách để xử lý 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
. Điều này cho phép bạn tiếp tục theo dõi hiệu suất trong các loại điều hướng này, ngay cả khi mức phân phối tổng thể có xu hướng âm. 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 như Thời gian cho đế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, bạn nên 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 đối với Chỉ số quan trọng chính của trang web
Các chỉ số quan trọng về trang web đo lường trải nghiệm của người dùng đối với 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 thấy quá trình khôi phục bfcache nhanh hơn so với quá trình tải toàn bộ trang, nên các chỉ số quan trọng về trang web phải phản ánh điều này. Xét cho cùng, 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 thao tá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 giá trị của các chỉ số đó bằng cách sử dụng các API web hiện có:
- Đối với Thời gian hiển thị nội dung lớn nhất (LCP), hãy sử dụng delta giữa dấu thời gian của sự kiện
pageshow
và dấu thời gian của khung được vẽ tiếp theo, vì tất cả các phần tử trong khung sẽ được vẽ cùng một lúc. Trong trường hợp khôi phục bfcache, LCP và FCP giống nhau. - Đối với chỉ số Lượt tương tác đến nội dung hiển thị tiếp theo (INP), hãy tiếp tục sử dụng Trình quan sát hiệu suất hiện có, nhưng đặt lại giá trị INP hiện tại về 0.
- Đối với Mức thay đổi bố cục tích luỹ (CLS), hãy tiếp tục sử dụng Trình quan sát hiệu suất hiện có, nhưng đặt lại giá trị CLS hiện tại về 0.
Để biết thêm thông tin về mức độ ảnh hưởng của bfcache đối với từng chỉ số, hãy xem các trang hướng dẫn về chỉ số cho các Chỉ số quan trọng chính của trang web. Để biết ví dụ cụ thể về cách triển khai các phiên bản bfcache của các chỉ số này, hãy tham khảo PR thêm các chỉ số này vào thư viện JS web-vitals.
Thư viện JavaScript web-vitals hỗ trợ 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
- Lưu vào bộ nhớ đệm trong Firefox (bfcache trong Firefox)
- Bộ nhớ đệm trang (bfcache trong Safari)
- Bộ nhớ đệm cho thao tác tiến/lùi: hành vi hiển thị trên web (sự khác biệt về bfcache giữa các trình duyệt)
- người kiểm thử bfcache (kiểm thử xem các API và sự kiện khác nhau ảnh hưởng như thế nào đến bfcache trong trình duyệt)
- Yếu tố thay đổi hiệu suất: Bộ nhớ đệm cho thao tác tiến/lùi của trình duyệt (một nghiên cứu điển hình của Smashing Magazine cho thấy sự cải thiện đáng kể về Chỉ số quan trọng chính của trang web bằng cách bật bfcache)