Hỗ trợ trình duyệt
Đôi khi, các trình duyệt hiện đại sẽ tạm ngưng hoặc loại bỏ hoàn toàn các trang khi tài nguyên hệ thống bị hạn chế. Trong tương lai, trình duyệt muốn chủ động làm việc này để tiêu thụ ít điện năng và bộ nhớ hơn. API Vòng đời trang cung cấp các trình bổ trợ vòng đời để các trang của bạn có thể xử lý an toàn các biện pháp can thiệp của trình duyệt này mà không ảnh hưởng đến trải nghiệm người dùng. Hãy xem API để biết liệu bạn có nên triển khai các tính năng này trong ứng dụng của mình hay không.
Thông tin khái quát
Vòng đời ứng dụng là một cách chính mà các hệ điều hành hiện đại quản lý tài nguyên. Trên Android, iOS và các phiên bản Windows gần đây, hệ điều hành có thể khởi động và dừng ứng dụng bất cứ lúc nào. Điều này cho phép các nền tảng này đơn giản hoá và phân bổ lại tài nguyên ở nơi mang lại lợi ích tốt nhất cho người dùng.
Trên web, trước đây không có vòng đời nào như vậy và các ứng dụng có thể tồn tại vô thời hạn. Khi có nhiều trang web đang chạy, các tài nguyên hệ thống quan trọng như bộ nhớ, CPU, pin và mạng có thể bị đăng ký quá mức, dẫn đến trải nghiệm người dùng cuối không tốt.
Mặc dù từ lâu, nền tảng web đã có các sự kiện liên quan đến trạng thái vòng đời, chẳng hạn như load
, unload
và visibilitychange
, nhưng những sự kiện này chỉ cho phép nhà phát triển phản hồi với các thay đổi về trạng thái vòng đời do người dùng khởi tạo. Để web hoạt động đáng tin cậy trên các thiết bị có công suất thấp (và nói chung là tiết kiệm tài nguyên hơn trên tất cả các nền tảng), trình duyệt cần có cách chủ động thu hồi và phân bổ lại tài nguyên hệ thống.
Trên thực tế, các trình duyệt hiện nay đã tích cực áp dụng các biện pháp để tiết kiệm tài nguyên cho các trang trong thẻ nền và nhiều trình duyệt (đặc biệt là Chrome) muốn làm nhiều việc hơn nữa để giảm thiểu mức sử dụng tài nguyên tổng thể.
Vấn đề là nhà phát triển không có cách nào để chuẩn bị cho những loại biện pháp can thiệp do hệ thống khởi tạo này hoặc thậm chí không biết rằng các biện pháp can thiệp này đang diễn ra. Điều này có nghĩa là trình duyệt cần phải thận trọng hoặc có nguy cơ làm hỏng trang web.
API Vòng đời trang cố gắng giải quyết vấn đề này bằng cách:
- Giới thiệu và chuẩn hoá khái niệm về các trạng thái vòng đời trên web.
- Xác định các trạng thái mới do hệ thống khởi tạo cho phép trình duyệt giới hạn tài nguyên mà các thẻ ẩn hoặc không hoạt động có thể sử dụng.
- Tạo các API và sự kiện mới cho phép nhà phát triển web phản hồi các lượt chuyển đổi đến và đi từ các trạng thái mới do hệ thống khởi tạo này.
Giải pháp này cung cấp khả năng dự đoán mà các nhà phát triển web cần để xây dựng các ứng dụng có khả năng chống chịu với các biện pháp can thiệp của hệ thống, đồng thời cho phép trình duyệt tối ưu hoá tài nguyên hệ thống một cách mạnh mẽ hơn, cuối cùng mang lại lợi ích cho tất cả người dùng web.
Phần còn lại của bài đăng này sẽ giới thiệu các tính năng mới của Vòng đời trang và khám phá mối liên hệ của chúng với tất cả các trạng thái và sự kiện hiện có trên nền tảng web. Công cụ này cũng sẽ đưa ra các đề xuất và phương pháp hay nhất cho các loại công việc mà nhà phát triển nên (và không nên) làm ở mỗi trạng thái.
Tổng quan về các trạng thái và sự kiện trong Vòng đời trang
Tất cả trạng thái Vòng đời trang đều riêng biệt và loại trừ lẫn nhau, nghĩa là một trang chỉ có thể ở một trạng thái tại một thời điểm. Ngoài ra, hầu hết các thay đổi đối với trạng thái vòng đời của một trang thường được ghi nhận thông qua các sự kiện DOM (xem các đề xuất dành cho nhà phát triển cho mỗi trạng thái để biết các trường hợp ngoại lệ).
Có lẽ cách dễ nhất để giải thích các trạng thái Vòng đời trang – cũng như các sự kiện báo hiệu chuyển đổi giữa các trạng thái đó – là dùng một sơ đồ:
Tiểu bang
Bảng sau đây giải thích chi tiết về từng trạng thái. Tệp này cũng liệt kê các trạng thái có thể xảy ra trước và sau cũng như các sự kiện mà nhà phát triển có thể sử dụng để quan sát các thay đổi.
Tiểu bang | Mô tả |
---|---|
Đang hoạt động |
Một trang ở trạng thái đang hoạt động nếu trang đó hiển thị và có tiêu điểm nhập.
Các trạng thái trước đó có thể xảy ra:
Các trạng thái có thể tiếp theo: |
Thụ động |
Một trang ở trạng thái thụ động nếu trang đó hiển thị và không có tiêu điểm đầu vào.
Các trạng thái có thể xảy ra trước đó:
Các trạng thái tiếp theo có thể xảy ra: |
Ẩn |
Một trang ở trạng thái ẩn nếu trang đó không hiển thị (và chưa bị đóng băng, loại bỏ hoặc chấm dứt).
Các trạng thái trước đó có thể xảy ra:
Các trạng thái tiếp theo có thể xảy ra: |
Đã bị treo |
Ở trạng thái bị cố định, trình duyệt sẽ tạm ngưng thực thi các
tác vụ
có thể bị đóng băng trong
hàng đợi tác vụ của trang cho đến khi trang không được cố định. Điều này có nghĩa là các tính năng như trình hẹn giờ JavaScript và lệnh gọi lại tìm nạp sẽ không chạy. Các tác vụ đang chạy có thể hoàn tất (quan trọng nhất là lệnh gọi lại Các trình duyệt cố định các trang như một cách để duy trì mức sử dụng CPU/pin/dữ liệu. Ngoài ra, những trình duyệt này cũng là một cách để di chuyển tiến/lùi nhanh hơn – tránh phải tải lại toàn bộ trang.
Các trạng thái trước đó có thể xảy ra:
Các trạng thái tiếp theo có thể xảy ra: |
Đã chấm dứt |
Một trang ở trạng thái đã chấm dứt sau khi trình duyệt bắt đầu tải xuống và xoá khỏi bộ nhớ. Không có tác vụ mới nào có thể bắt đầu ở trạng thái này và các tác vụ đang chạy có thể bị huỷ nếu chạy quá lâu.
Các trạng thái trước đó có thể xảy ra:
Các trạng thái có thể tiếp theo: |
Đã loại bỏ |
Một trang sẽ ở trạng thái đã loại bỏ khi bị trình duyệt huỷ tải để tiết kiệm tài nguyên. Không có tác vụ, lệnh gọi lại sự kiện hoặc bất kỳ loại JavaScript nào có thể chạy ở trạng thái này, vì việc loại bỏ thường xảy ra trong các điều kiện hạn chế về tài nguyên, khi không thể bắt đầu các quy trình mới. Ở trạng thái đã loại bỏ, người dùng thường thấy được chính thẻ đó (bao gồm cả tiêu đề thẻ và biểu tượng trang) mặc dù trang đã biến mất.
Các trạng thái trước đó có thể xảy ra:
Các trạng thái tiếp theo có thể xảy ra: |
Sự kiện
Các trình duyệt gửi nhiều sự kiện, nhưng chỉ một phần nhỏ trong số đó báo hiệu sự thay đổi có thể xảy ra đối với trạng thái Vòng đời trang. Bảng sau đây trình bày tất cả các sự kiện liên quan đến vòng đời và liệt kê các trạng thái mà các sự kiện đó có thể chuyển đổi đến và từ.
Tên | Thông tin chi tiết |
---|---|
focus
|
Một phần tử DOM đã nhận được tiêu điểm.
Lưu ý: sự kiện
Các trạng thái có thể trước đó:
Các trạng thái hiện tại có thể có: |
blur
|
Một phần tử DOM đã mất tiêu điểm.
Lưu ý: sự kiện
Các trạng thái trước đó có thể có:
Các trạng thái hiện tại có thể xuất hiện: |
visibilitychange
|
Giá trị |
freeze
*
|
Trang này vừa bị đóng băng. Mọi tác vụ có thể đóng băng trong hàng đợi tác vụ của trang sẽ không được bắt đầu.
Các trạng thái trước đó có thể có:
Các trạng thái hiện tại có thể là: |
resume
*
|
Trình duyệt đã tiếp tục một trang bị treo.
Các trạng thái trước đó có thể xảy ra:
Các trạng thái hiện tại có thể có: |
pageshow
|
Mục nhập nhật ký phiên đang được chuyển đến. Đó có thể là một lượt tải trang hoàn toàn mới hoặc một trang được lấy từ
bộ nhớ đệm cho thao tác tiến/lùi. Nếu trang được lấy từ bộ nhớ đệm cho thao tác tiến/lùi, thì thuộc tính
Các trạng thái trước đó có thể xảy ra: |
pagehide
|
Một mục nhật ký phiên đang được truy cập. Nếu người dùng đang chuyển đến một trang khác và trình duyệt có thể thêm trang hiện tại vào bộ nhớ đệm lui/tiến để sử dụng lại sau, thì thuộc tính
Các trạng thái trước đó có thể có:
Các trạng thái hiện tại có thể áp dụng: |
beforeunload
|
Cửa sổ, tài liệu và tài nguyên của tài liệu sắp được huỷ tải. Tài liệu vẫn hiển thị và sự kiện vẫn có thể huỷ tại thời điểm này.
Lưu ý quan trọng: bạn chỉ nên sử dụng sự kiện
Các trạng thái trước đó có thể có:
Các trạng thái hiện tại có thể có: |
unload
|
Trang đang được huỷ tải.
Cảnh báo: Bạn không nên sử dụng sự kiện
Các trạng thái trước đó có thể có:
Các trạng thái hiện tại có thể có: |
* Cho biết một sự kiện mới do Page Lifecycle API xác định
Các tính năng mới được thêm vào Chrome 68
Biểu đồ trước cho thấy 2 trạng thái do hệ thống khởi tạo chứ không phải do người dùng khởi tạo: đã được treo và đã loại bỏ. Như đã đề cập trước đó, các trình duyệt hiện nay đôi khi đã đóng băng và loại bỏ các thẻ bị ẩn (theo quyết định của họ), nhưng nhà phát triển không có cách nào để biết khi nào điều này xảy ra.
Trong Chrome 68, nhà phát triển hiện có thể quan sát thời điểm một thẻ ẩn bị đóng băng và
được mở băng bằng cách theo dõi các sự kiện freeze
và resume
trên document
.
document.addEventListener('freeze', (event) => {
// The page is now frozen.
});
document.addEventListener('resume', (event) => {
// The page has been unfrozen.
});
Từ Chrome 68, đối tượng document
hiện bao gồm một thuộc tính
wasDiscarded
trên Chrome dành cho máy tính (chúng tôi đang theo dõi khả năng hỗ trợ Android trong vấn đề này). Để xác định xem một trang có bị loại bỏ khi ở trong thẻ ẩn hay không, bạn có thể kiểm tra giá trị của thuộc tính này tại thời điểm tải trang (lưu ý: phải tải lại các trang đã bị loại bỏ để sử dụng lại).
if (document.wasDiscarded) {
// Page was previously discarded by the browser while in a hidden tab.
}
Để được tư vấn về những việc quan trọng cần làm trong các sự kiện freeze
và resume
, cũng như cách xử lý và chuẩn bị cho việc các trang bị loại bỏ, hãy xem các đề xuất dành cho nhà phát triển đối với từng trạng thái.
Các phần tiếp theo sẽ cung cấp thông tin tổng quan về cách các tính năng mới này phù hợp với các trạng thái và sự kiện hiện có của nền tảng web.
Cách quan sát các trạng thái Vòng đời trang trong mã
Ở trạng thái đang hoạt động, thụ động và ẩn, bạn có thể chạy mã JavaScript để xác định trạng thái Vòng đời trang hiện tại từ các API nền tảng web hiện có.
const getState = () => {
if (document.visibilityState === 'hidden') {
return 'hidden';
}
if (document.hasFocus()) {
return 'active';
}
return 'passive';
};
Mặt khác, bạn chỉ có thể phát hiện trạng thái đã đóng băng và đã chấm dứt trong trình nghe sự kiện tương ứng (freeze
và pagehide
) khi trạng thái đang thay đổi.
Cách quan sát các thay đổi về trạng thái
Dựa trên hàm getState()
được xác định trước đó, bạn có thể quan sát tất cả các thay đổi về trạng thái của Vòng đời trang bằng mã sau.
// Stores the initial state using the `getState()` function (defined above).
let state = getState();
// Accepts a next state and, if there's been a state change, logs the
// change to the console. It also updates the `state` value defined above.
const logStateChange = (nextState) => {
const prevState = state;
if (nextState !== prevState) {
console.log(`State change: ${prevState} >>> ${nextState}`);
state = nextState;
}
};
// Options used for all event listeners.
const opts = {capture: true};
// These lifecycle events can all use the same listener to observe state
// changes (they call the `getState()` function to determine the next state).
['pageshow', 'focus', 'blur', 'visibilitychange', 'resume'].forEach((type) => {
window.addEventListener(type, () => logStateChange(getState()), opts);
});
// The next two listeners, on the other hand, can determine the next
// state from the event itself.
window.addEventListener('freeze', () => {
// In the freeze event, the next state is always frozen.
logStateChange('frozen');
}, opts);
window.addEventListener('pagehide', (event) => {
// If the event's persisted property is `true` the page is about
// to enter the back/forward cache, which is also in the frozen state.
// If the event's persisted property is not `true` the page is
// about to be unloaded.
logStateChange(event.persisted ? 'frozen' : 'terminated');
}, opts);
Mã này thực hiện 3 việc:
- Đặt trạng thái ban đầu bằng hàm
getState()
. - Xác định một hàm chấp nhận trạng thái tiếp theo và nếu có thay đổi, hãy ghi lại các thay đổi trạng thái vào bảng điều khiển.
- Thêm trình nghe sự kiện ghi lại cho tất cả sự kiện vòng đời cần thiết, từ đó gọi
logStateChange()
, truyền vào trạng thái tiếp theo.
Xin lưu ý rằng tất cả trình nghe sự kiện đều được thêm vào window
và tất cả đều truyền {capture: true}
.
Dưới đây là một vài lý do dẫn đến trường hợp này:
- Không phải sự kiện nào trong Vòng đời trang cũng có cùng một mục tiêu.
pagehide
vàpageshow
được kích hoạt trênwindow
;visibilitychange
,freeze
vàresume
được kích hoạt trêndocument
, cònfocus
vàblur
được kích hoạt trên các phần tử DOM tương ứng. - Hầu hết các sự kiện này không tạo chuỗi bọt (bong bóng), tức là không thể thêm trình nghe sự kiện không ghi lại vào một phần tử gốc chung và quan sát tất cả các sự kiện đó.
- Giai đoạn chụp thực thi trước giai đoạn mục tiêu hoặc giai đoạn bong bóng, vì vậy, việc thêm trình nghe vào đó giúp đảm bảo chúng chạy trước khi mã khác có thể huỷ chúng.
Đề xuất dành cho nhà phát triển cho từng trạng thái
Là nhà phát triển, bạn cần phải hiểu rõ các trạng thái trong Vòng đời trang và biết cách quan sát các trạng thái đó trong mã vì loại công việc bạn nên (và không nên) làm phụ thuộc phần lớn vào trạng thái của trang.
Ví dụ: việc hiển thị thông báo tạm thời cho người dùng rõ ràng là không hợp lý nếu trang đang ở trạng thái ẩn. Mặc dù ví dụ này khá rõ ràng, nhưng có một số đề xuất khác không rõ ràng đến mức đáng kể.
Tiểu bang | Đề xuất dành cho nhà phát triển |
---|---|
Active |
Trạng thái đang hoạt động là thời điểm quan trọng nhất đối với người dùng và do đó, đây là thời điểm quan trọng nhất để trang của bạn phản hồi với hoạt động đầu vào của người dùng. Bạn nên giảm mức độ ưu tiên của mọi tác vụ không phải giao diện người dùng có thể chặn luồng chính xuống thời gian không hoạt động hoặc giảm tải cho một trình chạy web. |
Passive |
Ở trạng thái thụ động, người dùng không tương tác với trang nhưng vẫn có thể xem trang. Điều này có nghĩa là các bản cập nhật giao diện người dùng và ảnh động vẫn sẽ mượt mà, nhưng thời điểm diễn ra các bản cập nhật này ít quan trọng hơn. Khi trang thay đổi từ đang hoạt động thành không hoạt động, đó là thời điểm thích hợp để duy trì trạng thái ứng dụng chưa lưu. |
Khi trang chuyển từ trạng thái thụ động sang ẩn, người dùng có thể sẽ không tương tác lại với trang đó cho đến khi trang được tải lại. Quá trình chuyển đổi sang trạng thái ẩn cũng thường là thay đổi trạng thái cuối cùng mà nhà phát triển có thể quan sát một cách đáng tin cậy (điều này đặc biệt đúng trên thiết bị di động, vì người dùng có thể đóng các thẻ hoặc chính ứng dụng trình duyệt, đồng thời các sự kiện Điều này có nghĩa là bạn nên coi trạng thái ẩn là trạng thái có thể kết thúc phiên của người dùng. Nói cách khác, hãy duy trì mọi trạng thái ứng dụng chưa lưu và gửi mọi dữ liệu phân tích chưa gửi. Bạn cũng nên ngừng cập nhật giao diện người dùng (vì người dùng sẽ không thấy các bản cập nhật đó) và bạn nên dừng mọi tác vụ mà người dùng không muốn chạy ở chế độ nền. |
|
Frozen |
Ở trạng thái đã đóng băng, các tác vụ có thể đóng băng trong hàng đợi tác vụ sẽ bị tạm ngưng cho đến khi trang được huỷ đóng băng — điều này có thể không bao giờ xảy ra (ví dụ: nếu trang bị loại bỏ). Điều này có nghĩa là khi trang thay đổi từ ẩn thành đóng băng, bạn phải dừng mọi bộ hẹn giờ hoặc huỷ mọi kết nối. Nếu bị đóng băng, những kết nối này có thể ảnh hưởng đến các thẻ đang mở khác trong cùng một nguồn gốc hoặc ảnh hưởng đến khả năng của trình duyệt để đưa trang vào bộ nhớ đệm lui/tiến. Cụ thể, bạn cần:
Bạn cũng nên duy trì mọi trạng thái chế độ xem động (ví dụ: vị trí cuộn trong chế độ xem danh sách vô hạn) thành Nếu trang chuyển từ trạng thái bị cố định về trạng thái bị ẩn, thì bạn có thể mở lại mọi kết nối đã đóng hoặc bắt đầu lại mọi cuộc thăm dò ý kiến mà bạn đã dừng khi trang bị đóng băng ban đầu. |
Terminated |
Thông thường, bạn không cần làm gì khi một trang chuyển sang trạng thái đã chấm dứt. Vì các trang đang được tải xuống do hành động của người dùng luôn đi qua trạng thái ẩn trước khi chuyển sang trạng thái đã chấm dứt, nên trạng thái ẩn là nơi logic kết thúc phiên (ví dụ: duy trì trạng thái ứng dụng và báo cáo cho số liệu phân tích) được thực hiện. Ngoài ra (như đã đề cập trong đề xuất về trạng thái bị ẩn), nhà phát triển cần phải biết rằng trong nhiều trường hợp, không thể phát hiện một cách đáng tin cậy quá trình chuyển sang trạng thái đã chấm dứt (đặc biệt là trên thiết bị di động). Vì vậy, những nhà phát triển phụ thuộc vào sự kiện chấm dứt (ví dụ: |
Discarded |
Nhà phát triển không thể quan sát trạng thái đã loại bỏ tại thời điểm một trang bị loại bỏ. Điều này là do các trang thường bị loại bỏ trong các điều kiện ràng buộc về tài nguyên và việc huỷ đóng băng một trang chỉ để cho phép tập lệnh chạy để phản hồi một sự kiện loại bỏ là không thể trong hầu hết các trường hợp. Do đó, bạn nên chuẩn bị cho khả năng loại bỏ trong quá trình thay đổi từ ẩn thành đóng băng, sau đó bạn có thể phản hồi việc khôi phục trang đã loại bỏ tại thời điểm tải trang bằng cách kiểm tra |
Xin nhắc lại, vì độ tin cậy và thứ tự của các sự kiện trong vòng đời không được triển khai nhất quán trong tất cả các trình duyệt, nên cách dễ nhất để làm theo lời khuyên trong bảng là sử dụng PageLifecycle.js.
Các API vòng đời cũ cần tránh
Bạn nên tránh các sự kiện sau nếu có thể.
Sự kiện huỷ tải
Nhiều nhà phát triển coi sự kiện unload
là lệnh gọi lại được đảm bảo và sử dụng sự kiện này làm tín hiệu kết thúc phiên để lưu trạng thái và gửi dữ liệu phân tích, nhưng việc này rất không đáng tin cậy, đặc biệt là trên thiết bị di động! Sự kiện unload
không kích hoạt trong nhiều tình huống huỷ tải thông thường, bao gồm cả việc đóng một thẻ từ trình chuyển đổi thẻ trên thiết bị di động hoặc đóng ứng dụng trình duyệt từ trình chuyển đổi ứng dụng.
Vì lý do này, bạn nên luôn dựa vào sự kiện visibilitychange
để xác định thời điểm một phiên kết thúc và xem trạng thái ẩn là thời điểm đáng tin cậy gần đây nhất để lưu dữ liệu ứng dụng và người dùng.
Hơn nữa, việc chỉ có một trình xử lý sự kiện unload
đã đăng ký (thông qua onunload
hoặc addEventListener()
) có thể ngăn trình duyệt chuyển các trang vào bộ nhớ đệm cho thao tác tiến/lùi để tải tiến và lùi nhanh hơn.
Trong tất cả trình duyệt hiện đại, bạn nên luôn sử dụng sự kiện pagehide
để phát hiện các lượt tải trang có thể xảy ra (còn gọi là trạng thái đã chấm dứt) thay vì sự kiện unload
. Nếu cần hỗ trợ Internet Explorer phiên bản 10 trở xuống, bạn nên phát hiện sự kiện pagehide
và chỉ sử dụng unload
nếu trình duyệt không hỗ trợ pagehide
:
const terminationEvent = 'onpagehide' in self ? 'pagehide' : 'unload';
window.addEventListener(terminationEvent, (event) => {
// Note: if the browser is able to cache the page, `event.persisted`
// is `true`, and the state is frozen rather than terminated.
});
Sự kiện beforeunload
Sự kiện beforeunload
có vấn đề tương tự như sự kiện unload
, trong đó, trước đây, sự hiện diện của sự kiện beforeunload
có thể khiến các trang không đủ điều kiện sử dụng bộ nhớ đệm cho thao tác tiến/lùi. Các trình duyệt hiện đại không có quy định hạn chế này. Mặc dù để đề phòng, một số trình duyệt sẽ không kích hoạt sự kiện beforeunload
khi cố gắng đưa một trang vào bộ nhớ đệm cho thao tác tiến/lùi, điều này có nghĩa là sự kiện đó không đáng tin cậy làm tín hiệu kết thúc phiên.
Ngoài ra, một số trình duyệt (bao gồm cả Chrome) yêu cầu người dùng tương tác trên trang trước khi cho phép sự kiện beforeunload
kích hoạt, ảnh hưởng thêm đến độ tin cậy của sự kiện này.
Một điểm khác biệt giữa beforeunload
và unload
là có cách sử dụng hợp pháp beforeunload
. 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 lưu và sẽ mất các thay đổi đó nếu tiếp tục huỷ tải trang.
Vì có những lý do hợp lệ để sử dụng beforeunload
, bạn chỉ thêm trình nghe beforeunload
khi người dùng có các thay đổi chưa lưu, sau đó xoá các thay đổi đó ngay sau khi lưu.
Nói cách khác, đừng làm việc này (vì thao tác này thêm trình nghe beforeunload
vô điều kiện):
addEventListener('beforeunload', (event) => {
// A function that returns `true` if the page has unsaved changes.
if (pageHasUnsavedChanges()) {
event.preventDefault();
// Legacy support for older browsers.
return (event.returnValue = true);
}
});
Thay vào đó, hãy thực hiện việc này (vì nó chỉ thêm trình nghe beforeunload
khi cần và xoá trình nghe khi không cần thiết):
const beforeUnloadListener = (event) => {
event.preventDefault();
// Legacy support for older browsers.
return (event.returnValue = true);
};
// A function that invokes a callback when the page has unsaved changes.
onPageHasUnsavedChanges(() => {
addEventListener('beforeunload', beforeUnloadListener);
});
// A function that invokes a callback when the page's unsaved changes are resolved.
onAllChangesSaved(() => {
removeEventListener('beforeunload', beforeUnloadListener);
});
Câu hỏi thường gặp
Tại sao không có trạng thái "đang tải"?
Page Lifecycle API xác định các trạng thái tách biệt và loại trừ lẫn nhau. Vì một trang có thể được tải ở trạng thái đang hoạt động, thụ động hoặc ẩn, đồng thời trang có thể thay đổi trạng thái – hoặc thậm chí bị chấm dứt – trước khi tải xong, nên trạng thái tải riêng biệt không có ý nghĩa trong mô hình này.
Trang của tôi hoạt động rất quan trọng khi bị ẩn, làm cách nào để tôi ngăn trang bị đóng băng hoặc bị huỷ?
Có nhiều lý do chính đáng để trang web không nên bị treo trong khi chạy ở trạng thái ẩn. Ví dụ rõ ràng nhất là một ứng dụng phát nhạc.
Cũng có những trường hợp Chrome có thể gặp rủi ro khi loại bỏ một trang, chẳng hạn như nếu trang đó chứa một biểu mẫu có dữ liệu đầu vào chưa được người dùng gửi hoặc nếu trang đó có trình xử lý beforeunload
cảnh báo khi trang đang tải xuống.
Hiện tại, Chrome sẽ thận trọng khi loại bỏ các trang và chỉ làm như vậy khi chắc chắn rằng việc này sẽ không ảnh hưởng đến người dùng. Ví dụ: các trang được quan sát thấy thực hiện bất kỳ thao tác nào sau đây trong khi ở trạng thái ẩn sẽ không bị loại bỏ trừ khi gặp phải các hạn chế tài nguyên nghiêm trọng:
- Phát âm thanh
- Sử dụng WebRTC
- Cập nhật tiêu đề bảng hoặc biểu tượng trang chủ
- Hiển thị cảnh báo
- Gửi thông báo đẩy
Đối với các tính năng danh sách hiện tại dùng để xác định xem có thể đóng băng hoặc loại bỏ một thẻ một cách an toàn hay không, hãy xem: Phương pháp phỏng đoán để đóng băng và loại bỏ trong Chrome.
Bộ nhớ đệm cho thao tác tiến/lùi là gì?
Bộ nhớ đệm cho thao tác tiến/lùi là một thuật ngữ dùng để mô tả tính năng tối ưu hoá thao tác điều hướng mà một số trình duyệt triển khai để giúp sử dụng các nút tiến và lùi nhanh hơn.
Khi người dùng di chuyển khỏi một trang, các trình duyệt này sẽ đóng băng một phiên bản của trang đó để có thể nhanh chóng tiếp tục trong trường hợp người dùng quay lại bằng nút quay lại hoặc tiến. Hãy nhớ rằng việc thêm trình xử lý sự kiện unload
sẽ ngăn việc tối ưu hoá này.
Đối với mọi ý định và mục đích, hoạt động treo này có chức năng giống như các trình duyệt đóng băng thực hiện để bảo toàn CPU/pin; vì lý do đó, nó được coi là một phần của trạng thái vòng đời bị treo.
Nếu không thể chạy các API không đồng bộ ở trạng thái bị đóng băng hoặc bị chấm dứt, làm cách nào để lưu dữ liệu vào IndexedDB?
Ở trạng thái bị đóng băng và bị chấm dứt, các tác vụ có thể đóng băng trong hàng đợi tác vụ của trang sẽ bị tạm ngưng, tức là bạn không thể sử dụng các API không đồng bộ và dựa trên lệnh gọi lại như IndexedDB một cách đáng tin cậy.
Trong tương lai, chúng tôi sẽ thêm một phương thức commit()
vào các đối tượng IDBTransaction
. Phương thức này sẽ giúp nhà phát triển thực hiện các giao dịch chỉ có thể ghi một cách hiệu quả mà không cần lệnh gọi lại. Nói cách khác, nếu nhà phát triển chỉ ghi dữ liệu vào IndexedDB và không thực hiện giao dịch phức tạp bao gồm các thao tác đọc và ghi, thì phương thức commit()
sẽ có thể hoàn tất trước khi hàng đợi tác vụ bị tạm ngưng (giả sử cơ sở dữ liệu IndexedDB đã mở).
Tuy nhiên, đối với mã cần hoạt động ngay hôm nay, nhà phát triển có hai lựa chọn:
- Sử dụng bộ nhớ phiên: Bộ nhớ phiên có tính đồng bộ và được duy trì trong các lần huỷ trang.
- Sử dụng IndexedDB từ worker dịch vụ: worker dịch vụ có thể lưu trữ dữ liệu trong IndexedDB sau khi trang bị chấm dứt hoặc bị loại bỏ. Trong trình nghe sự kiện
freeze
hoặcpagehide
, bạn có thể gửi dữ liệu đến worker dịch vụ thông quapostMessage()
và worker dịch vụ có thể xử lý việc lưu dữ liệu.
Kiểm thử ứng dụng ở các trạng thái bị treo và bị loại bỏ
Để kiểm thử cách ứng dụng của bạn hoạt động ở trạng thái bị đóng băng và bị loại bỏ, bạn có thể truy cập vào chrome://discards
để thực sự đóng băng hoặc loại bỏ bất kỳ thẻ nào đang mở.
Điều này cho phép bạn đảm bảo trang của mình xử lý chính xác các sự kiện freeze
và resume
cũng như cờ document.wasDiscarded
khi các trang được tải lại sau khi bị loại bỏ.
Tóm tắt
Nhà phát triển muốn tôn trọng tài nguyên hệ thống của thiết bị người dùng nên xây dựng ứng dụng của họ theo các trạng thái Vòng đời trang. Điều quan trọng là các trang web không tiêu thụ quá nhiều tài nguyên hệ thống trong những trường hợp mà người dùng không mong muốn
Càng có nhiều nhà phát triển bắt đầu triển khai API Vòng đời trang mới, trình duyệt càng an toàn hơn khi đóng băng và loại bỏ các trang không được sử dụng. Điều này có nghĩa là trình duyệt sẽ tiêu thụ ít bộ nhớ, CPU, pin và tài nguyên mạng hơn, mang lại lợi ích cho người dùng.