Hỗ trợ trình duyệt
Các trình duyệt hiện đại ngày nay đôi khi sẽ tạm ngưng hoặc huỷ chúng hoàn toàn khi tài nguyên hệ thống bị hạn chế. Trong tương lai, các trình duyệt sẽ muốn thực hiện việc này chủ động để tiết kiệm pin và bộ nhớ. Page Lifecycle API cung cấp các hook trong vòng đời để các trang của bạn có thể xử lý các trình duyệt này một cách an toàn mà không ảnh hưởng đến trải nghiệm người dùng. Hãy xem API để xem 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 của ứng dụng là một cách quan trọng mà các hệ điều hành hiện đại quản lý của chúng tôi. Trên Android, iOS và các phiên bản Windows gần đây, bạn có thể khởi động ứng dụng và bị ngừng bất kỳ lúc nào bởi hệ điều hành. Nhờ đó, các nền tảng này có thể đơn giản hoá và phân bổ lại các tài nguyên 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ể được giữ lại tồn tại vô thời hạn. Với số lượng lớn trang web đang chạy, hệ thống quan trọng các tài nguyên 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 kém.
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
— như load
,
unload
và
visibilitychange
— những sự kiện này chỉ cho phép nhà phát triển
để phản hồ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
một cách đáng tin cậy trên các thiết bị tiết kiệm pin (và chú ý hơn về tài nguyên nói chung trên
tất cả nền tảng) thì cần có một cách để chủ động xác nhận lại và phân bổ lại hệ thống
của chúng tôi.
Trên thực tế, các trình duyệt hiện nay đã thực hiện những biện pháp chủ động để tiết kiệm tài nguyên cho các trang trong tab 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 — nhằm giảm bớt dấu ấn tổng thể về nguồn lực của họ.
Vấn đề là nhà phát triển không có cách nào để chuẩn bị cho những loại do hệ thống gây ra hay thậm chí biết rằng các biện pháp đó đ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.
Page Lifecycle API 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 các tài nguyên có thể bị sử dụng bởi các thẻ ẩn hoặc không hoạt độ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 chuyển đổi sang và từ các trạng thái mới do hệ thống khởi tạo.
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ọi lại sự can thiệp của hệ thống, đồng thời cho phép trình duyệt tích cực tối ưu hoá tài nguyên hệ thống, mà cuối cùng là 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 cũng như khám phá mối liên hệ giữa chúng với tất cả trạng thái hiện có của nền tảng web và sự kiện. Nền tảng 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 mỗi lần. Và 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ó thể quan sát được thông qua các sự kiện DOM (xem đề xuất của 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 chúng — là bằ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. Bảng này cũng liệt kê các khả năng các trạng thái có thể xuất hiện 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 những thay đổi.
Tiểu bang | Mô tả |
---|---|
Đang hoạt động |
Một trang sẽ ở trạng thái đang hoạt động nếu đang hiển thị và có tâm điểm nhập.
Những trạng thái có thể trước đó:
Những trạng thái có thể tiếp theo: |
Bị động |
Một trang sẽ chuyển sang trạng thái thụ động nếu trang đó vẫn hiển thị và có không có tâm điểm nhập.
Những trạng thái có thể trước đó:
Những trạng thái có thể tiếp theo: |
Đã ẩn |
Trang ở trạng thái bị ẩn nếu không hiển thị (và không bị treo, bị loại bỏ hoặc chấm dứt).
Những trạng thái có thể trước đó:
Những trạng thái có thể tiếp theo: |
Đã bị treo |
Ở trạng thái bị treo, trình duyệt sẽ tạm ngưng thực thi
có thể đóng băng
nhiệm vụ trong phần
hàng đợi công việc cho đến khi trang được bỏ cố định. Điều này có nghĩa là những thứ như
Các bộ tính giờ JavaScript và lệnh gọi lại tìm nạp không chạy. Đã chạy
công việc có thể hoàn tất (quan trọng nhất là
Trình duyệt cố định các trang như một cách để duy trì việc sử dụng CPU/pin/dữ liệu; chúng cũng là một cách để kích hoạt nhanh hơn thao tác tiến/lùi – tránh phải xem toàn bộ trang tải lại.
Những trạng thái có thể trước đó:
Những trạng thái có thể tiếp theo: |
Đã chấm dứt |
Trang sẽ ở trạng thái đã chấm dứt sau khi bắt đầu được được trình duyệt huỷ tải và xoá khỏi bộ nhớ. Không các tác vụ mới có thể bắt đầu ở trạng thái này và các tác vụ đang thực hiện có thể bị loại bỏ nếu chạy quá lâu.
Những trạng thái có thể trước đó:
Những trạng thái có thể tiếp theo: |
Đã huỷ |
Một trang ở trạng thái đã loại bỏ khi bị huỷ tải bằng trình duyệt để 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 JavaScript thuộc bất kỳ loại nào cũng có thể chạy ở trạng thái này, vì thường bị loại bỏ xảy ra trong những hạn chế về tài nguyên, trong đó việc bắt đầu các quy trình mới là không thể. Ở trạng thái đã loại bỏ, chính thẻ đó (bao gồm cả tiêu đề thẻ và biểu tượng trang web) thường hiển thị cho người dùng ngay cả khi trang đã biến mất.
Những trạng thái có thể trước đó:
Những trạng thái có thể tiếp theo: |
Sự kiện
Các trình duyệt gửi đi nhiều sự kiện, nhưng chỉ một phần nhỏ trong số đó báo hiệu thay đổi có thể xảy ra trong trạng thái Vòng đời trang. Bảng sau đây trình bày tất cả sự kiện liên quan đến vòng đời và liệt kê những trạng thái mà chúng có thể chuyển đổi và chuyển sang.
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
Những trạng thái có thể trước đó:
Các trạng thái hiện tại có thể áp dụng: |
blur
|
Một phần tử DOM bị mất tiêu điểm.
Lưu ý: sự kiện
Những trạng thái có thể trước đó:
Các trạng thái hiện tại có thể áp dụng: |
visibilitychange
|
của tài liệu
Giá trị |
freeze
*
|
Trang này vừa bị đóng băng. Bất kỳ hạng nào có thể đóng băng trong hàng đợi tác vụ của trang sẽ không bắt đầu.
Những trạng thái có thể trước đó:
Các trạng thái hiện tại có thể áp dụng: |
resume
*
|
Trình duyệt đã tiếp tục một trang bị treo.
Những trạng thái có thể trước đó:
Các trạng thái hiện tại có thể áp dụng: |
pageshow
|
Mục nhập nhật ký phiên đang được chuyển đến. Đây có thể là một 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
Thông tin này được lấy từ bộ nhớ đệm cho thao tác tiến/lùi,
Thuộc tính
Những trạng thái có thể trước đó:
Các trạng thái hiện tại có thể áp dụng: |
pagehide
|
Mục nhập nhật ký phiên đang được truyền tải. Nếu người dùng đang điều hướng đến một trang khác và trình duyệt có thể thêm
trang hiện tại để bật tính năng quay lại/chuyển tiếp
bộ nhớ đệm để sử dụng lại sau này, thuộc tính
Những trạng thái có thể trướ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 trong đó sắp bị huỷ tải. Tài liệu vẫn xuất hiện và sự kiện vẫn có thể huỷ tại thời điểm này điểm.
Lưu ý quan trọng: sự kiện
Những trạng thái có thể trước đó:
Các trạng thái hiện tại có thể áp dụng: |
unload
|
Trang đang bị huỷ tải.
Cảnh báo:
không bao giờ nên sử dụng sự kiện
Những trạng thái có thể trước đó:
Các trạng thái hiện tại có thể áp dụng: |
* 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 hệ thống khởi tạo do người dùng yêu cầu: bị cố định và bị loại bỏ. Như đã đề cập trước đó, các trình duyệt hiện nay đôi khi bị treo và huỷ các thẻ ẩn (theo ý mình), nhưng nhà phát triển không có cách nào để biết khi nào điều này đang diễn ra.
Giờ đây, trong Chrome 68, nhà phát triển có thể quan sát thời điểm một thẻ ẩn bị đóng băng và
không bị đóng băng bằng cách lắng nghe freeze
và resume
sự kiện vào 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
giờ đây bao gồm một
wasDiscarded
tài sản trên Chrome dành cho máy tính (chúng tôi đang theo dõi khả năng hỗ trợ của Android trong vấn đề này). Để xác định liệu một trang có bị huỷ khi đang ở trạng thái ẩn hay không
, bạn có thể kiểm tra giá trị của thuộc tính này vào thời gian tải trang (lưu ý:
các trang đã loại bỏ phải được tải lại để sử dụng lại).
if (document.wasDiscarded) {
// Page was previously discarded by the browser while in a hidden tab.
}
Để nhận lời khuyên về những việc quan trọng cần làm trong freeze
và resume
sự kiện, cũng như cách xử lý và chuẩn bị cho các trang bị loại bỏ, hãy xem
đề xuất của nhà phát triển cho 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 những tính năng mới này hoạt động 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 trạng thái Vòng đời trang trong mã
Ở trạng thái chủ động, thụ động và ẩn trạng thái thì có thể chạy mã JavaScript xác định Trạng thái Vòng đời trang từ API nền tảng web hiện có.
const getState = () => {
if (document.visibilityState === 'hidden') {
return 'hidden';
}
if (document.hasFocus()) {
return 'active';
}
return 'passive';
};
Các trạng thái đã được đóng băng và chấm dứt, trên
mặt khác, chỉ có thể phát hiện được trong trình nghe sự kiện tương ứng
(freeze
và pagehide
) theo trạng thái hiện tạ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 Trang
Trạng thái vòng đời thay đổi bằng đoạn 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, ghi lại các thay đổi về trạng thái vào bảng điều khiển.
- Thêm
quay
trình nghe sự kiện cho tất cả các sự kiện cần thiết trong vòng đời, sau đó gọi
logStateChange()
, truyền ở trạng thái tiếp theo.
Một điều cần lưu ý về mã này là tất cả các trình nghe sự kiện đều được thêm
đến window
và tất cả đều vượt qua
{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 tất cả sự kiện Vòng đời trang đều 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
,focus
vàblur
sẽ đượ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 có bong bóng, nghĩa là không thể thêm trình nghe sự kiện không nắm bắt một phần tử đối tượng cấp trên chung và quan sát tất cả trong số chúng.
- Giai đoạn chụp ảnh thực thi trước giai đoạn mục tiêu hoặc giai đoạn bong bóng, nên việc thêm trình nghe giúp đảm bảo chúng sẽ chạy trước khi mã khác có thể huỷ chúng.
Đề xuất của nhà phát triển cho mỗi trạng thái
Là nhà phát triển, bạn cần hiểu rõ các trạng thái của Vòng đời trang và biết cách quan sát chúng trong mã bởi vì loại công việc bạn nên làm (và nên không) đang thực hiện phụ thuộc phần lớn vào trạng thái của trang.
Ví dụ: việc hiển thị một thông báo tạm thời rõ ràng là không hợp lý cho người dùng nếu trang ở trạng thái ẩn. Mặc dù ví dụ này khá hiển nhiên, có những đề xuất khác không rõ ràng đến mức đáng để liệt kê.
Tiểu bang | Đề xuất của nhà phát triển |
---|---|
Active |
Trạng thái đang hoạt động là thời gian quan trọng nhất đối với người dùng và do đó thời điểm quan trọng nhất để trang của bạn thích ứng 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 đến khoả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 họ vẫn có thể xem nội dung đó. Tức là các bản cập nhật giao diện người dùng và ảnh động vẫn sẽ trơn tru, nhưng thời điểm xảy ra những cập nhật này ít quan trọng hơn. Khi trang thay đổi từ chủ động sang thụ động, đó là thời điểm thích hợp để lưu giữ trạng thái ứng dụng chưa lưu. |
Khi trang chuyển từ trạng thái bị động sang bị ẩn, có thể người dùng sẽ không tương tác lại với tệp đó cho đến khi tệp được tải lại. Quá trình chuyển đổi sang ẩn cũng thường là lần thay đổi trạng thái sau cùng
mà nhà phát triển có thể ghi nhận được một cách đáng tin cậy (điều này đặc biệt đúng với
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 và
Điều này có nghĩa là bạn nên coi trạng thái ẩn là trạng thái có khả năng kết thúc của người dùng. Nói cách khác, hãy duy trì mọi trạng thái chưa lưu của ứng dụng và gửi mọi dữ liệu phân tích chưa được 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 cập nhật giao diện người dùng) bởi người dùng) và bạn nên dừng mọi tác vụ mà người dùng không muốn đang chạy trong nền. |
|
Frozen |
Ở trạng thái bị treo, nhiệm vụ có thể cố định trong hàng đợi tác vụ sẽ bị tạm ngưng cho đến khi trang không bị cố định. Đ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ừ bị ẩn thành bị đóng băng bạn cần phải dừng mọi đồng hồ hẹn giờ hoặc phá vỡ những kết nối nếu bị treo, có thể ảnh hưởng đến các thẻ đang mở khác ở cùng nguồn gốc hoặc ảnh hưởng đến khả năng đặt trang vào phần tử bộ nhớ đệm cho thao tác tiến/lùi. Cụ thể, điều quan trọng là bạn phải:
Bạn cũng nên duy trì mọi trạng thái xem động (ví dụ: vị trí cuộn
ở chế độ xem danh sách vô hạn) để
Nếu trang chuyển từ trạng thái bị treo trở lại bị ẩn, 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 đã dừng khi trang bị đóng băng lần đầu. |
Terminated |
Thường thì bạn không cần thực hiện bất kỳ hành động nào khi trang chuyển đổi sang trạng thái đã chấm dứt. Vì các trang bị huỷ tải do hành động của người dùng luôn ở trạng thái ẩn trước khi chuyển sang trạng thái đã chấm dứt 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 Analytics) là thực hiện. Ngoài ra (như đã đề cập trong các đề xuất cho
trạng thái ẩn), thì nhà phát triển rất cần phải nhận ra
rằng việc chuyển sang trạng thái đã chấm dứt không thể được đảm bảo một cách đáng tin cậy
phát hiện trong nhiều trường hợp (đặ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
đối với sự kiện chấm dứt tài khoản (ví dụ: |
Discarded |
Nhà phát triển không thể quan sát trạng thái đã loại bỏ tại khi một trang bị hủy. Điều này là do các trang thường bị loại bỏ trong các hạn chế về tài nguyên và huỷ cố định một trang chỉ để cho phép đơn giản là không thể chạy tập lệnh để phản hồi sự kiện huỷ trong hầu hết các trường hợp. Do đó, bạn nên chuẩn bị cho khả năng bị huỷ trong
thay đổi từ ẩn thành bị đóng băng, sau đó bạn có thể
phản ứng với việc khôi phục trang bị loại bỏ vào thời gian tải trang bằng cách
đang kiểm tra |
Một lần nữa, vì độ tin cậy và thứ tự của các sự kiện trong vòng đời không phải là được triển khai một cách nhất quán trong tất cả trình duyệt, 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 "unload"
Nhiều nhà phát triển coi sự kiện unload
là một lệnh gọi lại được đảm bảo và sử dụng sự kiện đó như
tín hiệu cuối phiên để lưu trạng thái và gửi dữ liệu phân tích, nhưng thực hiện việc này
cực kỳ 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 dỡ hàng thông thường, bao gồm cả việc đóng một tab khỏi tab
trình chuyển đổi 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, tốt hơn là bạn nên dựa vào
Sự kiện visibilitychange
để xác định thời điểm một phiên hoạt động
kết thúc và xem xét trạng thái ẩn
thời điểm đáng tin cậy cuối cùng để lưu dữ liệu người dùng và ứng dụng.
Hơn nữa, sự hiện diện đơn thuần của trình xử lý sự kiện unload
đã đăng ký (thông qua
onunload
hoặc addEventListener()
) có thể khiến trình duyệt không thể
để đưa các trang vào bộ nhớ đệm cho thao tác tiến/lùi để nhanh hơn
tải lùi và tiến.
Trong tất cả cá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 số lượt tải trang có thể bị gỡ tải (còn gọi là
trạng thái đã chấm dứt) thay vì sự kiện unload
. Nếu bạn
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ể ngăn các trang
đủ điều kiện dùng bộ nhớ đệm cho thao tác tiến/lùi. Trình duyệt hiện đại
không có hạn chế này. Mặc dù một số trình duyệt sẽ không kích hoạt để đề phòng
sự kiện beforeunload
khi cố gắng đưa một trang vào chế độ tiến/lùi
bộ nhớ đệm, tức là sự kiện không đáng tin cậy dưới dạng tín hiệu cuối phiên.
Ngoài ra, một số trình duyệt (bao gồm Chrome)
yêu cầu sự tương tác của người dùng trên trang trước khi cho phép sự kiện beforeunload
kích hoạt, ảnh hưởng nhiều hơn đến độ tin cậy của nó.
Một điểm khác biệt giữa beforeunload
và unload
là có
trường hợp sử dụng hợp pháp beforeunload
. Ví dụ: khi bạn muốn cảnh báo người dùng
họ sẽ mất các thay đổi chưa lưu 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 nên
chỉ thêm trình nghe beforeunload
khi người dùng có các thay đổi chưa lưu, sau đó
hãy xoá các mật khẩu đó ngay sau khi lưu.
Nói cách khác, không làm việc này (vì tính năng này sẽ 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 làm điều này (vì nó chỉ thêm trình nghe beforeunload
khi
cần thiết và xoá 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ó nút "tải" trạng thá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 chủ động, thụ động hoặc ẩn và vì nó có thể thay đổi trạng thái (hoặc thậm chí bị chấm dứt) trước khi tải xong, 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 để không đóng băng trang web 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.
Ngoài ra, trong một số trường hợp, Chrome có nguy cơ loại bỏ trang,
như nếu nó chứa biểu mẫu với thông tin người dùng chưa gửi hoặc nếu nó có
Trình xử lý beforeunload
cảnh báo khi trang đang bị huỷ tải.
Hiện tại, Chrome sẽ thận trọng khi loại bỏ trang và chỉ làm vậy khi tin tưởng là việc đó sẽ không ảnh hưởng đến người dùng. Ví dụ: các trang phát hiện thấy bất kỳ hành động nào sau đây khi ở trạng thái ẩn sẽ không bị loại bỏ trừ phi chịu các hạn chế cực kỳ nghiêm trọng về tài nguyên:
- Đang phát âm thanh
- Sử dụng WebRTC
- Cập nhật tiêu đề bảng hoặc biểu tượng trang web
- Hiện thông báo
- Đang gửi thông báo đẩy
Đối với các tính năng hiện tại trong danh sách dùng để xác định xem một thẻ có thể an toàn hay không đông lạnh hoặc bị loại bỏ, xem bài viết: Khoa học kỹ thuật đông lạnh và Đang 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ả một tối ưu hoá điều hướng mà một số trình duyệt triển khai bằng cách sử dụng nút quay lại nút tiến nhanh hơn.
Khi người dùng điều hướng khỏi một trang, các trình duyệt này sẽ đóng băng phiên bản của trang đó
để trang có thể nhanh chóng tiếp tục chạy 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 unload
trình xử lý sự kiện ngăn chặn việc tối ưu hoá này.
Đối với tất cả ý định và mục đích, quá trình treo này có chức năng giống như các trình duyệt đóng băng hoạt động để tiết kiệm CPU/pin; vì lý do đó, được coi là một phần của trạng thái vòng đời bị treo.
Nếu tôi không thể chạy API không đồng bộ ở trạng thái bị cố định hoặc chấm dứt, làm cách nào để lưu dữ liệu vào IndexedDB?
Ở trạng thái bị treo và chấm dứt, tác vụ có thể cố định trong hàng đợi tác vụ của trang bị tạm ngưng, tức là các API không đồng bộ và API dựa trên lệnh gọi lại như IndexedDB không thể sử dụng một cách đáng tin cậy.
Trong tương lai, chúng ta 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 những giao dịch chỉ ghi hiệu quả
không yêu cầu gọi lại. Nói cách khác, nếu nhà phát triển chỉ viết
dữ liệu đến IndexedDB và không thực hiện giao dịch phức tạp bao gồm các lần đọ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ụ được
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ì qua các lần huỷ trang.
- Sử dụng IndexedDB từ trình chạy dịch vụ của bạn: trình chạy 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
freeze
hoặc Trình nghe sự kiệnpagehide
bạn có thể gửi dữ liệu đến trình chạy dịch vụ của mình quapostMessage()
! và trình chạy 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ử xem ứng dụng của bạn hoạt động như thế nào ở trạng thái bị treo và bị loại bỏ, bạn có thể truy cập
chrome://discards
để thực sự cố định hoặc loại bỏ bất kỳ
thẻ đang mở.
Việc này giúp bạn đảm bảo trang của bạn xử lý freeze
và resume
đúng cách
các sự kiện cũng như cờ document.wasDiscarded
khi các trang được tải lại sau
huỷ.
Tóm tắt
Những nhà phát triển muốn tôn trọng tài nguyên hệ thống trên thiết bị của người dùng nên xây dựng ứng dụng với sự lưu ý đến trạng thái Vòng đời trang. Điều quan trọng là các trang web không sử dụng quá nhiều tài nguyên hệ thống trong trường hợp người dùng không mong đợi
Càng nhiều nhà phát triển bắt đầu triển khai các API Vòng đời trang mới thì càng an toàn hơn sẽ dành cho trình duyệt đóng băng và loại bỏ các trang không được sử dụng. Chiến dịch này có nghĩa là trình duyệt sẽ tốn ít bộ nhớ, CPU, pin và tài nguyên mạng hơn, thì đây là lợi ích dành cho người dùng.