API Siklus Proses Halaman

Browser Support

  • Chrome: 68.
  • Edge: 79.
  • Firefox: not supported.
  • Safari: not supported.

Browser modern saat ini terkadang menangguhkan atau menghapus halaman sepenuhnya saat resource sistem terbatas. Pada masa mendatang, browser ingin melakukan hal ini secara proaktif, sehingga browser menggunakan lebih sedikit 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 Anda.

Latar belakang

Siklus proses aplikasi adalah cara utama sistem operasi modern mengelola resource. Di Android, iOS, dan versi Windows terbaru, aplikasi dapat dimulai dan dihentikan kapan saja oleh OS. Dengan demikian, platform ini dapat menyederhanakan dan mengalokasikan ulang sumber daya di tempat yang paling menguntungkan pengguna.

Di web, secara historis tidak ada siklus proses seperti itu, dan aplikasi dapat terus berjalan tanpa batas waktu. Dengan banyaknya halaman web yang berjalan, resource sistem penting 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 dapat berfungsi dengan andal di perangkat berdaya rendah (dan secara umum lebih hemat resource di semua platform), browser memerlukan cara untuk secara proaktif merebut kembali dan mengalokasikan ulang resource sistem.

Faktanya, browser saat ini telah mengambil langkah-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 sedang terjadi. Artinya, browser harus berhati-hati atau berisiko merusak halaman web.

Page Lifecycle API berupaya menyelesaikan masalah ini dengan:

  • Memperkenalkan dan menstandardisasi konsep status siklus proses di web.
  • Menentukan status baru yang dimulai 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 tangguh terhadap intervensi sistem, dan memungkinkan browser mengoptimalkan resource sistem secara lebih agresif, yang pada akhirnya akan menguntungkan semua pengguna web.

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

Ringkasan status dan peristiwa Siklus Proses Halaman

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

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

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

Negara bagian

Tabel berikut menjelaskan setiap status secara mendetail. Dokumen ini juga mencantumkan kemungkinan status yang dapat terjadi sebelum dan sesudah, 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)
dibekukan (melalui peristiwa resume, lalu peristiwa 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 pageshow)

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)
dibekukan (melalui peristiwa resume, lalu peristiwa pageshow)

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

Periode frozen

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

Browser membekukan halaman untuk menghemat penggunaan CPU/baterai/data; browser juga melakukannya untuk memungkinkan 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 dihentikan setelah mulai dibatalkan pemuatannya dan dihapus dari memori oleh browser. Tidak ada tugas baru yang dapat dimulai dalam status ini, dan tugas yang sedang berlangsung dapat dihentikan jika berjalan terlalu lama.

Kemungkinan status sebelumnya:
tersembunyi (melalui peristiwa pagehide)

Kemungkinan status berikutnya:
TIDAK ADA

Dibatalkan

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

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

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

Kemungkinan status berikutnya:
TIDAK ADA

Acara

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

Nama Detail
focus

Elemen DOM telah menerima fokus.

Catatan: peristiwa focus tidak selalu menandakan perubahan status. Perubahan status hanya ditandai 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. Perubahan status hanya disinyalkan jika halaman tidak lagi memiliki fokus input (yaitu, halaman tidak hanya mengalihkan fokus dari satu elemen ke elemen lain).

Status sebelumnya yang mungkin:
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, meminimalkan 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 dalam antrean tugas halaman tidak akan dimulai.

Kemungkinan status sebelumnya:
tersembunyi

Kemungkinan status saat ini:
dibekukan

resume *

Browser telah melanjutkan halaman yang dibekukan.

Kemungkinan status sebelumnya:
frozen

Kemungkinan status saat ini:
active (jika diikuti oleh peristiwa pageshow)
passive (jika diikuti oleh peristiwa pageshow)
hidden

pageshow

Entri histori sesi sedang ditelusuri.

Hal ini dapat berupa pemuatan halaman yang benar-benar baru atau halaman yang diambil dari back/forward cache. Jika halaman diambil dari back/forward cache, properti persisted peristiwa adalah true, jika tidak, propertinya adalah false.

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

Kemungkinan status saat ini:
active
passive
hidden

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. Jika true, halaman memasuki status dibekukan, jika tidak, halaman memasuki status dihentikan.

Kemungkinan status sebelumnya:
tersembunyi

Kemungkinan status saat ini:
dibekukan (event.persisted benar, freeze peristiwa berikutnya)
dihentikan (event.persisted salah, unload peristiwa berikutnya)

beforeunload

Jendela, dokumen, dan resource-nya akan dihapus muatannya. Dokumen masih terlihat dan acara masih dapat dibatalkan pada saat ini.

Penting: peristiwa beforeunload hanya boleh digunakan untuk memberi tahu pengguna tentang perubahan yang belum disimpan. Setelah perubahan tersebut disimpan, acara akan dihapus. Jangan pernah ditambahkan tanpa syarat ke halaman, karena tindakan ini dapat menurunkan performa dalam beberapa kasus. Lihat bagian API lama untuk mengetahui detailnya.

Kemungkinan status sebelumnya:
tersembunyi

Kemungkinan status saat ini:
dihentikan

unload

Halaman sedang dibatalkan pemuatannya.

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:
dihentikan

* 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 oleh pengguna: dibekukan dan dihapus. Seperti yang disebutkan sebelumnya, browser saat ini terkadang membekukan dan menghapus tab tersembunyi (sesuai kebijakannya), tetapi developer tidak dapat mengetahui kapan hal ini terjadi.

Di Chrome 68, developer kini dapat mengamati saat tab tersembunyi dibekukan dan dibuka dengan memantau peristiwa freeze dan resume di 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 menyertakan properti wasDiscarded di Chrome desktop (dukungan Android sedang dilacak dalam masalah ini). Untuk menentukan apakah halaman dibuang saat berada di tab tersembunyi, Anda dapat memeriksa nilai properti ini pada waktu pemuatan halaman (catatan: halaman yang dibuang harus dimuat ulang untuk digunakan lagi).

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

Untuk mengetahui saran tentang hal-hal penting yang harus 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';
};

Status dibekukan dan dihentikan, di sisi lain, hanya dapat dideteksi di pemroses peristiwanya masing-masing (freeze dan pagehide) saat status berubah.

Cara mengamati perubahan status

Dengan fungsi getState() yang ditentukan sebelumnya, Anda dapat mengamati semua perubahan status PageLifecycle 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 pengambilan untuk semua peristiwa siklus proses yang diperlukan, yang pada gilirannya memanggil logStateChange(), dengan 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, serta focus dan blur diaktifkan di elemen DOM masing-masing.
  • Sebagian besar peristiwa ini tidak menggelembung, yang berarti tidak mungkin menambahkan pemroses peristiwa yang tidak menangkap ke elemen induk umum dan mengamati semua peristiwa tersebut.
  • Fase pengambilan dieksekusi sebelum fase target atau balon, jadi menambahkan pemroses di sana akan 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 harus (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 dicantumkan.

Negara Bagian Rekomendasi developer
Active

Status aktif adalah waktu paling penting bagi pengguna dan dengan demikian waktu paling penting bagi halaman Anda untuk merespons input pengguna.

Setiap pekerjaan non-UI yang dapat memblokir thread utama harus diturunkan prioritasnya ke periode tidak ada aktivitas atau dilepaskan ke pekerja web.

Passive

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

Saat halaman berubah dari aktif menjadi pasif, ini adalah waktu yang tepat untuk mempertahankan status aplikasi yang belum 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 secara andal oleh developer (hal ini terutama berlaku di perangkat seluler, karena pengguna dapat menutup tab atau aplikasi browser itu sendiri, dan peristiwa beforeunload, pagehide, dan unload tidak dipicu 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 belum dikirim.

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

Frozen

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

Artinya, saat halaman berubah dari tersembunyi menjadi dibekukan, Anda harus menghentikan semua timer atau menghentikan semua koneksi yang, jika dibekukan, dapat memengaruhi tab lain yang terbuka di origin yang sama, atau memengaruhi kemampuan browser untuk menempatkan halaman di cache kembali/maju.

Khususnya, Anda harus:

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

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

Terminated

Umumnya, Anda tidak perlu melakukan tindakan apa pun saat halaman bertransisi ke status dihentikan.

Karena halaman yang dibongkar sebagai akibat dari tindakan pengguna selalu melalui status tersembunyi sebelum memasuki status dihentikan, status tersembunyi adalah tempat logika pengakhiran sesi (misalnya, mempertahankan status aplikasi dan melaporkan ke analisis) harus dilakukan.

Selain itu (seperti yang disebutkan dalam rekomendasi untuk status tersembunyi), developer harus 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. Hal ini karena halaman biasanya dihapus karena batasan resource, dan membuka halaman yang dibekukan hanya untuk mengizinkan skrip berjalan sebagai respons terhadap peristiwa penghapusan tidak mungkin dilakukan dalam sebagian besar kasus.

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

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

API siklus proses lama yang harus dihindari

Acara 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 pelepasan yang umum, termasuk menutup tab dari pengalih tab di perangkat seluler atau menutup aplikasi browser dari pengalih aplikasi.

Oleh karena itu, sebaiknya selalu mengandalkan peristiwa visibilitychange untuk menentukan kapan sesi berakhir, dan menganggap status tersembunyi sebagai waktu terakhir yang andal untuk menyimpan data aplikasi dan pengguna.

Selain itu, keberadaan pengendali peristiwa unload yang 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 pelepasan halaman (alias status dihentikan) daripada peristiwa unload. Jika Anda perlu mendukung Internet Explorer versi 10 dan yang lebih lama, Anda harus mendeteksi fitur 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, keberadaan 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 dalam 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, sehingga memengaruhi keandalannya.

Salah satu perbedaan antara beforeunload dan unload adalah bahwa ada penggunaan beforeunload yang sah. Misalnya, saat Anda ingin memperingatkan pengguna bahwa mereka memiliki perubahan yang belum disimpan yang akan hilang jika mereka melanjutkan pembatalan pemuatan halaman.

Karena ada alasan yang valid untuk menggunakan beforeunload, sebaiknya Anda hanya menambahkan pemroses beforeunload saat pengguna memiliki perubahan yang belum disimpan, lalu segera menghapusnya setelah perubahan 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.
    event.returnValue = true;
  }
});

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

const beforeUnloadListener = (event) => {
  event.preventDefault();

  // Legacy support for older browsers.
  event.returnValue = true;
};

// A function that adds a `beforeunload` listener if there are unsaved changes.
onPageHasUnsavedChanges(() => {
  addEventListener('beforeunload', beforeUnloadListener);
});

// A function that removes the `beforeunload` listener when the page's unsaved
// changes are resolved.
onAllChangesSaved(() => {
  removeEventListener('beforeunload', beforeUnloadListener);
});

FAQ

Mengapa tidak ada status "memuat"?

Page Lifecycle API menentukan status yang bersifat diskrit dan saling eksklusif. Karena halaman dapat dimuat dalam status aktif, pasif, atau tersembunyi, dan karena halaman dapat berubah 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 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 ketika Chrome akan berisiko jika membuang halaman, seperti jika halaman berisi formulir dengan input pengguna yang belum dikirim, atau jika halaman memiliki handler beforeunload yang memperingatkan saat halaman dibongkar.

Untuk saat ini, Chrome akan berhati-hati saat membuang halaman dan hanya melakukannya jika yakin tidak akan memengaruhi pengguna. Misalnya, halaman yang teramati melakukan salah satu hal 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 mengetahui fitur daftar saat ini yang digunakan untuk menentukan apakah tab dapat dibekukan atau dihapus dengan aman, lihat: Heuristik untuk Pembekuan & Penghapusan di Chrome.

Apa yang dimaksud dengan back/forward cache?

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

Saat pengguna keluar dari halaman, browser ini membekukan versi halaman tersebut sehingga dapat dilanjutkan dengan cepat jika pengguna kembali menggunakan tombol kembali atau maju. Ingatlah bahwa menambahkan unload event handler mencegah pengoptimalan ini dilakukan.

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

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

Dalam status dibekukan dan dihentikan, tugas yang dapat dibekukan dalam antrean tugas halaman ditangguhkan, yang berarti API asinkron dan berbasis callback tidak dapat digunakan secara andal.

Meskipun sebagian besar API IndexedDB berbasis callback, metode commit() pada antarmuka IDBTransaction menyediakan cara untuk memulai proses commit pada transaksi aktif tanpa menunggu peristiwa dari permintaan yang belum selesai dikirim. Hal ini memberikan cara yang andal untuk menyimpan data ke database IndexedDB di pemroses peristiwa freeze atau visibilitychange karena penerapan dijalankan langsung, bukan diantrekan dalam tugas terpisah.

Menguji aplikasi Anda dalam status dibekukan dan dibuang

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

UI Pembuangan Tab Chrome
UI Penghapusan Tab Chrome

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

Ringkasan

Developer yang ingin menghargai resource sistem perangkat pengguna harus membangun 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 menerapkan Page Lifecycle API baru, makin aman bagi browser untuk membekukan dan menghapus halaman yang tidak digunakan. Artinya, browser akan menggunakan lebih sedikit memori, CPU, baterai, dan resource jaringan, yang menguntungkan pengguna.