API Siklus Proses Halaman

Dukungan Browser

  • Chrome: 68.
  • Edge: 79.
  • Firefox: tidak didukung.
  • Safari: tidak didukung.x

Browser modern saat ini terkadang akan menangguhkan halaman atau menghapusnya sepenuhnya saat resource sistem dibatasi. Di masa mendatang, browser ingin melakukannya secara proaktif, sehingga lebih hemat daya dan memori. Page Lifecycle API menyediakan hook siklus proses sehingga halaman Anda dapat menangani intervensi browser ini dengan aman tanpa memengaruhi pengalaman pengguna. Lihat API untuk mengetahui apakah Anda harus menerapkan fitur ini di aplikasi.

Latar belakang

Siklus proses aplikasi adalah cara utama bagi sistem operasi modern untuk mengelola resource. Di Android, iOS, dan versi Windows terbaru, aplikasi dapat dimulai dan dihentikan kapan saja oleh OS. Hal ini memungkinkan platform ini menyederhanakan dan mengalihkan alokasi resource ke tempat yang paling menguntungkan pengguna.

Di web, secara historis tidak ada siklus proses seperti itu, dan aplikasi dapat terus aktif tanpa batas waktu. Dengan halaman web yang berjalan dalam jumlah besar, resource sistem kritis seperti memori, CPU, baterai, dan jaringan dapat kelebihan permintaan, sehingga menyebabkan pengalaman pengguna akhir yang buruk.

Meskipun platform web telah lama memiliki peristiwa yang terkait dengan status siklus proses — seperti load, unload, dan visibilitychange — peristiwa ini hanya memungkinkan developer merespons perubahan status siklus proses yang dimulai pengguna. Agar web berfungsi secara andal di perangkat dengan daya rendah (dan lebih hemat resource secara umum di semua platform), browser memerlukan cara untuk secara proaktif mengklaim kembali dan mengalokasikan ulang resource sistem.

Faktanya, browser saat ini sudah mengambil langkah aktif untuk menghemat resource untuk halaman di tab latar belakang, dan banyak browser (terutama Chrome) ingin melakukan lebih banyak hal ini — untuk mengurangi jejak resource secara keseluruhan.

Masalahnya adalah developer tidak memiliki cara untuk mempersiapkan jenis intervensi yang dimulai sistem ini atau bahkan mengetahui bahwa intervensi tersebut terjadi. Artinya, browser harus bersifat konservatif atau berisiko merusak halaman web.

Page Lifecycle API mencoba mengatasi masalah ini dengan:

  • Memperkenalkan dan menstandarkan konsep status siklus proses di web.
  • Menentukan status baru yang dimulai oleh sistem yang memungkinkan browser membatasi resource yang dapat digunakan oleh tab tersembunyi atau tidak aktif.
  • Membuat API dan peristiwa baru yang memungkinkan developer web merespons transisi ke dan dari status baru yang dimulai sistem ini.

Solusi ini memberikan prediktabilitas yang dibutuhkan developer web untuk membangun aplikasi yang tahan terhadap intervensi sistem, dan memungkinkan browser mengoptimalkan resource sistem secara lebih agresif, yang pada akhirnya menguntungkan semua pengguna web.

Bagian lain dari postingan ini akan memperkenalkan fitur Siklus Proses Halaman yang baru dan mempelajari hubungannya dengan semua status dan peristiwa platform web yang ada. Laporan ini juga akan memberikan rekomendasi dan praktik terbaik untuk jenis pekerjaan yang harus (dan tidak boleh) dilakukan developer di setiap status.

Ringkasan status dan peristiwa Siklus Proses Halaman

Semua status Siklus Proses Halaman bersifat terpisah dan saling eksklusif, yang berarti halaman hanya dapat berada dalam satu status dalam satu waktu. Selain itu, sebagian besar perubahan pada status siklus proses halaman umumnya dapat diamati melalui peristiwa DOM (lihat rekomendasi developer untuk setiap status untuk mengetahui pengecualian).

Mungkin cara termudah untuk menjelaskan status Siklus Proses Halaman — serta peristiwa yang menandakan transisi di antara status tersebut — adalah dengan diagram:

Representasi visual status dan alur peristiwa yang dijelaskan di seluruh dokumen ini.
Status dan alur peristiwa Page Lifecycle API.

Negara bagian

Tabel berikut menjelaskan setiap status secara mendetail. Diagram ini juga mencantumkan kemungkinan status yang dapat terjadi sebelum dan sesudahnya serta peristiwa yang dapat digunakan developer untuk mengamati perubahan.

Negara Bagian Deskripsi
Aktif

Halaman berada dalam status aktif jika terlihat dan memiliki fokus input.

Kemungkinan status sebelumnya:
pasif (melalui peristiwa focus)
beku (melalui peristiwa resume, lalu pageshow)

Kemungkinan status berikutnya:
pasif (melalui peristiwa blur)

Pasif

Halaman berada dalam status pasif jika terlihat dan tidak memiliki fokus input.

Kemungkinan status sebelumnya:
aktif (melalui peristiwa blur)
tersembunyi (melalui peristiwa visibilitychange)
dibekukan (melalui peristiwa resume, lalu peristiwa {21)/}{/2pageshow

Kemungkinan status berikutnya:
aktif (melalui peristiwa focus)
tersembunyi (melalui peristiwa visibilitychange)

Tersembunyi

Halaman berada dalam status tersembunyi jika tidak terlihat (dan belum dibekukan, dihapus, atau dihentikan).

Kemungkinan status sebelumnya:
pasif (melalui peristiwa visibilitychange)
beku (melalui peristiwa resume, lalu pageshow)

Kemungkinan status berikutnya:
pasif (melalui peristiwa visibilitychange)
beku (melalui peristiwa freeze)
dihapus (tidak ada peristiwa yang diaktifkan)
dihentikan (tidak ada peristiwa yang diaktifkan)

Beku

Dalam status beku, browser menangguhkan eksekusi tugas yang dapat dibekukan di antrean tugas halaman hingga halaman dicairkan. Artinya, hal-hal seperti timer JavaScript dan callback pengambilan tidak berjalan. Tugas yang sudah berjalan dapat selesai (yang paling penting adalah callback freeze), tetapi mungkin terbatas dalam hal yang dapat dilakukan dan berapa lama tugas tersebut dapat berjalan.

Browser membekukan halaman sebagai cara untuk menghemat penggunaan CPU/baterai/data; browser juga melakukannya sebagai cara untuk mengaktifkan navigasi kembali/maju yang lebih cepat — sehingga tidak perlu memuat ulang halaman secara penuh.

Kemungkinan status sebelumnya:
tersembunyi (melalui peristiwa freeze)

Kemungkinan status berikutnya:
aktif (melalui peristiwa resume, lalu peristiwa pageshow)
pasif (melalui peristiwa resume, lalu peristiwa pageshow)
tersembunyi (melalui peristiwa resume)
dihapus (tidak ada peristiwa yang diaktifkan)

Dihentikan

Halaman berada dalam status terminated setelah mulai di-unload dan dihapus dari memori oleh browser. Tidak ada tugas baru yang dapat dimulai dalam status ini, dan tugas yang sedang berlangsung mungkin akan dihentikan jika berjalan terlalu lama.

Kemungkinan status sebelumnya:
tersembunyi (melalui peristiwa pagehide)

Kemungkinan status berikutnya:
NONE

Dihapus

Halaman dalam status dihapus saat dihapus muatannya oleh browser untuk menghemat resource. Tidak ada tugas, callback peristiwa, atau jenis JavaScript apa pun yang dapat dijalankan dalam status ini, karena penghapusan biasanya terjadi karena batasan resource, yang tidak memungkinkan memulai proses baru.

Dalam status dihapus, tab itu sendiri (termasuk judul tab dan favicon) biasanya terlihat oleh pengguna meskipun halamannya sudah tidak ada.

Kemungkinan status sebelumnya:
tersembunyi (tidak ada peristiwa yang diaktifkan)
beku (tidak ada peristiwa yang diaktifkan)

Kemungkinan status berikutnya:
NONE

Acara

Browser mengirim banyak peristiwa, tetapi hanya sebagian kecil yang menandakan kemungkinan perubahan status Siklus Proses Halaman. Tabel berikut menguraikan semua peristiwa yang berkaitan dengan siklus proses dan mencantumkan status yang dapat ditransisikan.

Nama Detail
focus

Elemen DOM telah menerima fokus.

Catatan: peristiwa focus tidak selalu menandakan perubahan status. Hal ini hanya menandakan perubahan status jika halaman sebelumnya tidak memiliki fokus input.

Kemungkinan status sebelumnya:
pasif

Kemungkinan status saat ini:
aktif

blur

Elemen DOM telah kehilangan fokus.

Catatan: peristiwa blur tidak selalu menandakan perubahan status. Atribut ini hanya menandakan perubahan status jika halaman tidak lagi memiliki fokus input (yaitu halaman tidak hanya mengalihkan fokus dari satu elemen ke elemen lainnya).

Kemungkinan status sebelumnya:
aktif

Kemungkinan status saat ini:
pasif

visibilitychange

Nilai visibilityState dokumen telah berubah. Hal ini dapat terjadi saat pengguna membuka halaman baru, beralih tab, menutup tab, menciutkan atau menutup browser, atau beralih aplikasi di sistem operasi seluler.

Kemungkinan status sebelumnya:
pasif
tersembunyi

Kemungkinan status saat ini:
pasif
tersembunyi

freeze *

Halaman baru saja dibekukan. Setiap tugas yang dapat dibekukan di antrean tugas halaman tidak akan dimulai.

Kemungkinan status sebelumnya:
disembunyikan

Kemungkinan status saat ini:
beku

resume *

Browser telah melanjutkan halaman beku.

Kemungkinan status sebelumnya:
frozen

Kemungkinan status saat ini:
aktif (jika diikuti dengan peristiwa pageshow)
pasif (jika diikuti oleh peristiwa pageshow)
tersembunyi

pageshow

Entri histori sesi sedang dilalui.

Ini dapat berupa pemuatan halaman baru atau halaman yang diambil dari cache kembali/maju. Jika halaman diambil dari cache kembali/maju, properti persisted peristiwa adalah true, jika tidak, properti tersebut adalah false.

Kemungkinan status sebelumnya:
beku (peristiwa resume juga akan diaktifkan)

Kemungkinan status saat ini:
aktif
pasif
tersembunyi

pagehide

Entri histori sesi sedang dilalui.

Jika pengguna membuka halaman lain dan browser dapat menambahkan halaman saat ini ke cache kembali/maju untuk digunakan kembali nanti, properti persisted peristiwa adalah true. Saat true, halaman memasuki status beku, jika tidak, halaman tersebut memasuki status dihentikan.

Kemungkinan status sebelumnya:
tersembunyi

Kemungkinan status saat ini:
beku (event.persisted benar, peristiwa freeze akan mengikuti)
dihentikan (event.persisted salah, peristiwa unload akan mengikuti)

beforeunload

Jendela, dokumen, dan resource-nya akan segera dihapus muatannya. Dokumen masih terlihat dan peristiwa masih dapat dibatalkan pada tahap ini.

Penting: peristiwa beforeunload hanya boleh digunakan untuk memberi tahu pengguna tentang perubahan yang belum disimpan. Setelah perubahan tersebut disimpan, peristiwa harus dihapus. ID ini tidak boleh ditambahkan tanpa syarat ke halaman, karena dalam beberapa kasus, dapat mengganggu performa. Baca bagian API lama untuk mengetahui detailnya.

Kemungkinan status sebelumnya:
hidden

Kemungkinan status saat ini:
terminated

unload

Halaman sedang di-unload.

Peringatan: penggunaan peristiwa unload tidak pernah direkomendasikan karena tidak dapat diandalkan dan dapat menurunkan performa dalam beberapa kasus. Lihat bagian API lama untuk mengetahui detail selengkapnya.

Kemungkinan status sebelumnya:
tersembunyi

Kemungkinan status saat ini:
terminated

* Menunjukkan peristiwa baru yang ditentukan oleh Page Lifecycle API

Fitur baru yang ditambahkan di Chrome 68

Diagram sebelumnya menunjukkan dua status yang dimulai oleh sistem, bukan dimulai oleh pengguna: beku dan dihapus. Seperti yang disebutkan sebelumnya, browser saat ini terkadang membeku dan menghapus tab tersembunyi (sesuai kebijaksanaan mereka), tetapi developer tidak dapat mengetahui kapan hal ini terjadi.

Di Chrome 68, developer kini dapat mengamati saat tab tersembunyi dibekukan dan dibuka dengan memproses peristiwa freeze dan resume pada document.

document.addEventListener('freeze', (event) => {
  // The page is now frozen.
});

document.addEventListener('resume', (event) => {
  // The page has been unfrozen.
});

Mulai Chrome 68, objek document kini mencakup properti wasDiscarded di Chrome desktop (dukungan Android dilacak dalam masalah ini). Untuk menentukan apakah halaman dihapus saat berada di tab yang disembunyikan, Anda dapat memeriksa nilai properti ini pada waktu pemuatan halaman (catatan: halaman yang dihapus harus dimuat ulang untuk digunakan lagi).

if (document.wasDiscarded) {
  // Page was previously discarded by the browser while in a hidden tab.
}

Untuk mendapatkan saran tentang hal-hal yang penting dilakukan dalam peristiwa freeze dan resume, serta cara menangani dan mempersiapkan halaman yang dihapus, lihat rekomendasi developer untuk setiap status.

Beberapa bagian berikutnya menawarkan ringkasan tentang kesesuaian fitur baru ini dengan status dan peristiwa platform web yang ada.

Cara mengamati status Siklus Proses Halaman dalam kode

Dalam status aktif, pasif, dan tersembunyi, Anda dapat menjalankan kode JavaScript yang menentukan status Siklus Proses Halaman saat ini dari API platform web yang ada.

const getState = () => {
  if (document.visibilityState === 'hidden') {
    return 'hidden';
  }
  if (document.hasFocus()) {
    return 'active';
  }
  return 'passive';
};

Di sisi lain, status beku dan dihentikan hanya dapat dideteksi di pemroses peristiwa masing-masing (freeze dan pagehide) saat status berubah.

Cara mengamati perubahan status

Dengan fungsi getState() yang ditentukan sebelumnya, Anda dapat mengamati semua perubahan status Siklus Proses Halaman dengan kode berikut.

// 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);

Kode ini melakukan tiga hal:

  • Menetapkan status awal menggunakan fungsi getState().
  • Menentukan fungsi yang menerima status berikutnya dan, jika ada perubahan, mencatat perubahan status ke konsol.
  • Menambahkan pemroses peristiwa perekaman untuk semua peristiwa siklus proses yang diperlukan, yang pada akhirnya memanggil logStateChange(), yang meneruskan status berikutnya.

Satu hal yang perlu diperhatikan tentang kode ini adalah semua pemroses peristiwa ditambahkan ke window dan semuanya meneruskan {capture: true}. Ada beberapa alasan:

  • Tidak semua peristiwa Siklus Proses Halaman memiliki target yang sama. pagehide, dan pageshow diaktifkan di window; visibilitychange, freeze, dan resume diaktifkan di document, dan focus dan blur diaktifkan di elemen DOM masing-masing.
  • Sebagian besar peristiwa ini tidak menggelembung, yang berarti tidak mungkin menambahkan pemroses peristiwa yang tidak merekam ke elemen ancestor umum dan mengamati semuanya.
  • Fase pengambilan dieksekusi sebelum fase target atau bubble, sehingga menambahkan pemroses di sana membantu memastikan pemroses berjalan sebelum kode lain dapat membatalkannya.

Rekomendasi developer untuk setiap status

Sebagai developer, penting untuk memahami status Siklus Proses Halaman dan mengetahui cara mengamatinya dalam kode karena jenis pekerjaan yang seharusnya (dan tidak boleh Anda lakukan) sangat bergantung pada status halaman Anda.

Misalnya, tidak masuk akal untuk menampilkan notifikasi sementara kepada pengguna jika halaman dalam status tersembunyi. Meskipun contoh ini cukup jelas, ada rekomendasi lain yang tidak begitu jelas yang perlu dihitung.

Negara Bagian Rekomendasi developer
Active

Status active adalah waktu yang paling penting bagi pengguna dan dengan demikian, waktu yang paling penting bagi halaman Anda untuk menjadi responsif terhadap input pengguna.

Pekerjaan non-UI yang dapat memblokir thread utama harus diprioritaskan ke periode tidak ada aktivitas atau dialihkan ke pekerja web.

Passive

Dalam status pasif, pengguna tidak berinteraksi dengan halaman, tetapi mereka masih dapat melihatnya. Artinya, update dan animasi UI akan tetap lancar, tetapi waktu terjadinya update ini kurang penting.

Saat halaman berubah dari aktif menjadi pasif, ini adalah waktu yang tepat untuk mempertahankan status aplikasi yang tidak disimpan.

Hidden

Saat halaman berubah dari pasif menjadi tersembunyi, pengguna mungkin tidak akan berinteraksi lagi dengan halaman tersebut hingga halaman dimuat ulang.

Transisi ke tersembunyi juga sering kali merupakan perubahan status terakhir yang dapat diamati dengan andal oleh developer (terutama di perangkat seluler, karena pengguna dapat menutup tab atau aplikasi browser itu sendiri, dan peristiwa beforeunload, pagehide, dan unload tidak diaktifkan dalam kasus tersebut).

Artinya, Anda harus memperlakukan status tersembunyi sebagai kemungkinan akhir sesi pengguna. Dengan kata lain, pertahankan status aplikasi yang belum disimpan dan kirim data analisis yang tidak terkirim.

Anda juga harus berhenti membuat update UI (karena tidak akan dilihat oleh pengguna), dan Anda harus menghentikan tugas apa pun yang tidak diinginkan pengguna berjalan di latar belakang.

Frozen

Dalam status beku, tugas yang dapat dibekukan di antrean tugas ditangguhkan hingga halaman tidak dibekukan lagi — yang mungkin tidak pernah terjadi (misalnya, jika halaman dihapus).

Artinya, saat halaman berubah dari tersembunyi menjadi dibekukan, Anda harus menghentikan timer atau memutus koneksi yang, jika dibekukan, dapat memengaruhi tab terbuka lainnya di asal yang sama, atau memengaruhi kemampuan browser untuk menempatkan halaman di back/forward cache.

Secara khusus, Anda harus:

Anda juga harus mempertahankan status tampilan dinamis (misalnya, posisi scroll dalam tampilan daftar tanpa batas) ke sessionStorage (atau IndexedDB melalui commit()) yang ingin Anda pulihkan jika halaman dihapus dan dimuat ulang nanti.

Jika halaman bertransisi dari beku kembali ke tersembunyi, Anda dapat membuka kembali koneksi yang ditutup atau memulai ulang polling yang Anda hentikan saat halaman awalnya dibekukan.

Terminated

Biasanya, Anda tidak perlu melakukan tindakan apa pun saat halaman beralih ke status dihentikan.

Karena halaman yang di-unload sebagai hasil dari tindakan pengguna selalu melalui status tersembunyi sebelum memasuki status dihentikan, status tersembunyi adalah tempat logika penghentian sesi (misalnya, mempertahankan status aplikasi dan melaporkan ke analisis) harus dilakukan.

Selain itu (seperti yang disebutkan dalam rekomendasi untuk status tersembunyi), sangat penting bagi developer untuk menyadari bahwa transisi ke status dihentikan tidak dapat dideteksi dengan andal dalam banyak kasus (terutama di perangkat seluler), sehingga developer yang bergantung pada peristiwa penghentian (misalnya, beforeunload, pagehide, dan unload) kemungkinan akan kehilangan data.

Discarded

Status dihapus tidak dapat diamati oleh developer pada saat halaman dihapus. Ini karena halaman biasanya dibuang berdasarkan keterbatasan resource, dan mencairkan halaman hanya agar skrip dapat berjalan sebagai respons terhadap peristiwa penghapusan dalam kebanyakan kasus.

Oleh karena itu, Anda harus mempersiapkan kemungkinan penghapusan dalam perubahan dari hidden menjadi frozen, lalu Anda dapat bereaksi terhadap pemulihan halaman yang dihapus pada waktu pemuatan halaman dengan memeriksa document.wasDiscarded.

Sekali lagi, karena keandalan dan pengurutan peristiwa siklus proses tidak diterapkan secara konsisten di semua browser, cara termudah untuk mengikuti saran dalam tabel adalah menggunakan PageLifecycle.js.

API siklus proses lama yang harus dihindari

Peristiwa berikut sebaiknya dihindari jika memungkinkan.

Peristiwa penghapusan muatan

Banyak developer memperlakukan peristiwa unload sebagai callback yang dijamin dan menggunakannya sebagai sinyal akhir sesi untuk menyimpan status dan mengirim data analisis, tetapi melakukan hal ini sangat tidak dapat diandalkan, terutama di perangkat seluler. Peristiwa unload tidak diaktifkan dalam banyak situasi penghapusan muatan yang umum, termasuk menutup tab dari pengalih tab di perangkat seluler atau menutup aplikasi browser dari pengalih aplikasi.

Karena alasan ini, sebaiknya selalu mengandalkan peristiwa visibilitychange untuk menentukan kapan sesi berakhir, dan pertimbangkan status tersembunyi sebagai waktu terakhir yang dapat diandalkan untuk menyimpan data aplikasi dan pengguna.

Selain itu, keberadaan pengendali peristiwa unload terdaftar (melalui onunload atau addEventListener()) dapat mencegah browser menempatkan halaman di back/forward cache untuk pemuatan mundur dan maju yang lebih cepat.

Di semua browser modern, sebaiknya selalu gunakan peristiwa pagehide untuk mendeteksi kemungkinan penghapusan muatan halaman (alias status terminated), bukan peristiwa unload. Jika perlu mendukung Internet Explorer versi 10 dan yang lebih lama, sebaiknya Anda mendeteksi peristiwa pagehide dan hanya menggunakan unload jika browser tidak mendukung 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.
});

Peristiwa beforeunload

Peristiwa beforeunload memiliki masalah yang serupa dengan peristiwa unload, yaitu, secara historis, kehadiran peristiwa beforeunload dapat mencegah halaman memenuhi syarat untuk back-forward cache. Browser modern tidak memiliki batasan ini. Meskipun beberapa browser, sebagai tindakan pencegahan, tidak akan memicu peristiwa beforeunload saat mencoba memasukkan halaman ke cache kembali/maju, yang berarti peristiwa tersebut tidak dapat diandalkan sebagai sinyal akhir sesi. Selain itu, beberapa browser (termasuk Chrome) memerlukan interaksi pengguna di halaman sebelum mengizinkan peristiwa beforeunload diaktifkan, yang selanjutnya memengaruhi keandalannya.

Satu perbedaan antara beforeunload dan unload adalah ada penggunaan beforeunload yang sah. Misalnya, saat Anda ingin memperingatkan pengguna bahwa mereka memiliki perubahan yang belum disimpan, perubahan akan hilang jika mereka terus menghapus muatan halaman.

Karena ada alasan valid untuk menggunakan beforeunload, sebaiknya Anda hanya menambahkan pemroses beforeunload saat pengguna memiliki perubahan yang belum disimpan, lalu segera menghapusnya setelah disimpan.

Dengan kata lain, jangan lakukan ini (karena menambahkan pemroses beforeunload tanpa syarat):

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);
  }
});

Sebagai gantinya, lakukan hal ini (karena hanya menambahkan pemroses beforeunload saat diperlukan, dan menghapusnya jika tidak diperlukan):

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);
});

FAQ

Mengapa tidak ada status "loading"?

Page Lifecycle API mendefinisikan status menjadi diskret dan saling eksklusif. Karena halaman dapat dimuat dalam status aktif, pasif, atau tersembunyi, dan karena halaman dapat mengubah status—atau bahkan dihentikan—sebelum selesai dimuat, status pemuatan terpisah tidak masuk akal dalam paradigma ini.

Halaman saya melakukan tugas penting saat disembunyikan. Bagaimana cara mencegahnya agar tidak dibekukan atau dihapus?

Ada banyak alasan sah mengapa halaman web tidak boleh dibekukan saat berjalan dalam status tersembunyi. Contoh yang paling jelas adalah aplikasi yang memutar musik.

Ada juga situasi saat Chrome berisiko membuang halaman, seperti jika halaman berisi formulir dengan input pengguna yang belum dikirim, atau jika memiliki pengendali beforeunload yang memperingatkan saat halaman di-unload.

Untuk saat ini, Chrome akan bersikap konservatif saat menghapus halaman dan hanya melakukannya jika yakin tidak akan memengaruhi pengguna. Misalnya, halaman yang telah diamati melakukan tindakan berikut saat dalam status tersembunyi tidak akan dihapus kecuali dalam batasan resource yang ekstrem:

  • Memutar audio
  • Menggunakan WebRTC
  • Memperbarui judul tabel atau favicon
  • Menampilkan notifikasi
  • Mengirim notifikasi push

Untuk fitur daftar saat ini yang digunakan untuk menentukan apakah tab dapat dibekukan atau dihapus dengan aman, lihat: Heuristika untuk Pembekuan & Penghapusan di Chrome.

Apa yang dimaksud dengan back/forward cache?

Cache kembali/maju adalah istilah yang digunakan untuk menjelaskan pengoptimalan navigasi yang diterapkan oleh beberapa browser yang membuat penggunaan tombol kembali dan maju lebih cepat.

Saat pengguna keluar dari halaman, browser ini akan membekukan versi halaman tersebut sehingga dapat dilanjutkan dengan cepat jika pengguna membuka kembali menggunakan tombol kembali atau maju. Perlu diingat bahwa menambahkan pengendali peristiwa unload akan mencegah pengoptimalan ini.

Untuk semua tujuan dan maksud, pembekuan ini secara fungsional sama dengan browser pembekuan yang dilakukan untuk menghemat CPU/baterai; karena alasan itu, tindakan ini dianggap sebagai bagian dari status siklus proses beku.

Jika saya tidak dapat menjalankan API asinkron dalam status beku atau dihentikan, bagaimana cara menyimpan data ke IndexedDB?

Dalam status beku dan dihentikan, tugas yang dapat dibekukan di antrean tugas halaman akan ditangguhkan, yang berarti API asinkron dan berbasis callback seperti IndexedDB tidak dapat digunakan dengan andal.

Di masa mendatang, kita akan menambahkan metode commit() ke objek IDBTransaction, yang akan memberi developer cara untuk melakukan transaksi hanya tulis yang efektif dan tidak memerlukan callback. Dengan kata lain, jika developer hanya menulis data ke IndexedDB dan tidak melakukan transaksi kompleks yang terdiri dari pembacaan dan penulisan, metode commit() akan dapat diselesaikan sebelum task queue ditangguhkan (dengan asumsi bahwa database qwiklab sudah terbuka).

Namun, untuk kode yang harus berfungsi saat ini, developer memiliki dua opsi:

  • Gunakan Penyimpanan Sesi: Penyimpanan Sesi sinkron dan dipertahankan di seluruh penghapusan halaman.
  • Gunakan IndexedDB dari pekerja layanan Anda: pekerja layanan dapat menyimpan data di IndexedDB setelah halaman dihentikan atau dihapus. Di pemroses peristiwa freeze atau pagehide, Anda dapat mengirim data ke pekerja layanan melalui postMessage(), dan pekerja layanan dapat menangani penyimpanan data.

Menguji aplikasi Anda dalam status beku dan dihapus

Untuk menguji perilaku aplikasi dalam status dibekukan dan dihapus, Anda dapat membuka chrome://discards untuk benar-benar membekukan atau menghapus tab terbuka.

Chrome Menghapus UI
UI Chrome yang Dihapus

Hal ini memungkinkan Anda memastikan halaman menangani peristiwa freeze dan resume dengan benar serta tanda document.wasDiscarded saat halaman dimuat ulang setelah dihapus.

Ringkasan

Developer yang ingin menghormati resource sistem perangkat pengguna mereka harus mem-build aplikasi dengan mempertimbangkan status Siklus Proses Halaman. Sangat penting agar halaman web tidak menggunakan resource sistem secara berlebihan dalam situasi yang tidak diharapkan pengguna

Makin banyak developer yang mulai mengimplementasikan Page Lifecycle API yang baru, makin aman bagi browser untuk membekukan dan menghapus halaman yang tidak digunakan. Hal ini berarti browser akan menggunakan lebih sedikit memori, CPU, baterai, dan resource jaringan, yang merupakan keuntungan bagi pengguna.