API Siklus Proses Halaman

Dukungan Browser

  • 68
  • 79
  • x
  • x

Browser modern saat ini terkadang akan menangguhkan halaman atau menghapusnya sepenuhnya ketika resource sistem dibatasi. Di masa mendatang, browser ingin melakukan hal ini secara proaktif, agar mengonsumsi 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 melihat apakah Anda harus mengimplementasikan fitur-fitur ini di aplikasi.

Latar belakang

Siklus proses aplikasi adalah cara utama bagi sistem operasi modern untuk mengelola resource. Pada Android, iOS, dan versi Windows terbaru, aplikasi dapat dimulai dan dihentikan kapan saja oleh OS. Hal ini memungkinkan platform ini menyederhanakan dan mengalokasikan ulang resource di tempat yang memberikan manfaat terbaik bagi pengguna.

Di web, secara historis tidak ada siklus proses seperti itu, dan aplikasi dapat terus aktif tanpa batas. Dengan berjalannya sejumlah besar halaman web, resource sistem yang penting seperti memori, CPU, baterai, dan jaringan dapat mengalami kelebihan langganan, yang 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 untuk merespons perubahan status siklus proses yang dimulai oleh pengguna. Agar web dapat berfungsi dengan andal pada perangkat berdaya rendah (dan lebih sadar akan resource secara umum di semua platform), browser memerlukan cara untuk secara proaktif mengklaim kembali dan mengalokasikan ulang resource sistem.

Bahkan, browser saat ini telah melakukan 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 saat ini tidak memiliki cara untuk mempersiapkan diri terhadap jenis intervensi yang dimulai oleh sistem ini atau bahkan mengetahui bahwa intervensi tersebut sedang terjadi. Artinya, browser harus konservatif atau berisiko merusak halaman web.

Page Lifecycle API mencoba mengatasi masalah ini dengan:

  • Memperkenalkan dan menstandardisasi 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 oleh sistem ini.

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

Bagian selanjutnya dari postingan ini akan memperkenalkan fitur Siklus Proses Halaman baru dan mempelajari keterkaitannya dengan semua status dan peristiwa platform web yang ada. Bagian ini juga akan memberikan rekomendasi dan praktik terbaik untuk jenis pekerjaan yang boleh (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, artinya 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 pengecualian).

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

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

Status

Tabel berikut menjelaskan setiap status secara mendetail. Kode ini juga mencantumkan kemungkinan status yang dapat muncul sebelum dan sesudah, serta peristiwa yang dapat digunakan developer untuk mengamati perubahan.

Negara Bagian Deskripsi
Aktif

Halaman dalam status aktif jika terlihat dan memiliki fokus input.

Kemungkinan status sebelumnya:
pasif (melalui peristiwa focus)
beku (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)
frozen (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)
beku (melalui peristiwa resume, lalu peristiwa 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 frozen, browser akan menangguhkan eksekusi tugas yang dapat dibekukan di task queue halaman hingga halaman dibatalkan. Artinya, hal-hal seperti timer JavaScript dan callback pengambilan tidak akan berjalan. Tugas yang sudah berjalan dapat selesai (yang paling penting callback freeze), tetapi tugas yang dapat dilakukan dan durasi waktu berjalan mungkin terbatas.

Browser membekukan halaman sebagai cara untuk menghemat penggunaan CPU/baterai/data; browser juga melakukannya sebagai cara untuk memungkinkan navigasi mundur/maju yang lebih cepat sehingga menghindari kebutuhan pemuatan ulang halaman penuh.

Kemungkinan status sebelumnya:
disembunyikan (melalui peristiwa freeze)

Kemungkinan status berikutnya:
aktif (melalui peristiwa resume, lalu peristiwa pageshow)
pasif resume, kemudian peristiwa pageshowresume


Dihentikan

Halaman berada dalam status dihentikan setelah mulai dihapus muatannya 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:
disembunyikan (melalui peristiwa pagehide)

Kemungkinan status berikutnya:
TIDAK ADA

Dihapus

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

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

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

Kemungkinan status berikutnya:
TIDAK ADA

Peristiwa

Browser mengirim banyak peristiwa, tetapi hanya sebagian kecil yang menandakan kemungkinan perubahan pada status Siklus Proses Halaman. Tabel di bawah ini menguraikan semua peristiwa yang berkaitan dengan siklus proses dan mencantumkan status transisi yang dapat dilalui dan berasal dari peristiwa tersebut.

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. Hal ini hanya menandakan perubahan status jika halaman tidak lagi memiliki fokus input (yaitu halaman tidak hanya beralih 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, meminimalkan atau menutup browser, atau beralih aplikasi pada sistem operasi seluler.

Kemungkinan status sebelumnya:
pasif
tersembunyi

Kemungkinan status saat ini:
pasif
tersembunyi

freeze *

Halaman baru saja dibekukan. Semua tugas yang dapat dibekukan di task queue halaman tidak akan dimulai.

Kemungkinan status sebelumnya:
tersembunyi

Kemungkinan status saat ini:
frozen

resume *

Browser telah melanjutkan halaman yang dibekukan.

Kemungkinan status sebelumnya:
frozen

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

pageshow

Entri histori sesi sedang dilalui.

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

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

Kemungkinan status saat ini:
aktif
pasif
tersembunyi

pagehide

Entri histori sesi sedang dilintasi.

Jika pengguna membuka halaman lain dan browser dapat menambahkan halaman saat ini ke back/forward cache untuk digunakan kembali nanti, properti persisted peristiwa adalah true. Saat true, halaman akan memasuki status frozen, atau akan memasuki status dihentikan.

Kemungkinan status sebelumnya:
tersembunyi

Kemungkinan status saat ini:
frozen (event.persisted benar, freeze peristiwa diikuti)
dihentikan (event.persisted false, unload peristiwa mengikuti)

beforeunload

Jendela, dokumen, dan resource-nya akan 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. Elemen ini tidak boleh ditambahkan tanpa syarat ke halaman, karena dalam beberapa kasus, hal tersebut dapat menurunkan performa. Lihat bagian API lama untuk mengetahui detailnya.

Kemungkinan status sebelumnya:
tersembunyi

Kemungkinan status saat ini:
dihentikan

unload

Halaman sedang dihapus muatannya.

Peringatan: penggunaan peristiwa unload tidak direkomendasikan karena tidak dapat diandalkan dan dalam beberapa kasus dapat menurunkan performa. Lihat bagian API lama untuk 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 di atas menunjukkan dua status yang dimulai oleh sistem, bukan dimulai oleh pengguna: frozen dan discarded. Seperti yang disebutkan di atas, browser saat ini terkadang membekukan dan menghapus tab tersembunyi (sesuai pertimbangannya sendiri), tetapi developer tidak dapat mengetahui kapan hal ini terjadi.

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

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

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

Di Chrome 68, objek document kini juga menyertakan properti wasDiscarded. Untuk menentukan apakah halaman dihapus saat berada di tab tersembunyi, Anda dapat memeriksa nilai properti ini pada waktu pemuatan halaman (catatan: halaman yang dihapus harus dimuat ulang agar dapat digunakan lagi).

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

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

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

Mengamati status Siklus Proses Halaman dalam kode

Dalam status aktif, pasif, dan tersembunyi, kode JavaScript dapat dijalankan 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 frozen dan dihentikan hanya dapat dideteksi di pemroses peristiwa masing-masing (freeze dan pagehide) saat status berubah.

Mengamati perubahan status

Dengan membangun fungsi getState() yang ditentukan di atas, 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 di atas 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 penangkap peristiwa untuk semua peristiwa siklus proses yang diperlukan, yang kemudian akan memanggil logStateChange(), yang meneruskan status berikutnya.

Satu hal yang perlu diperhatikan tentang kode di atas 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 pada document, serta focus dan blur diaktifkan pada elemen DOM-nya masing-masing.
  • Sebagian besar peristiwa ini tidak dijadikan balon, yang berarti tidak mungkin untuk menambahkan pemroses peristiwa yang tidak menangkap ke elemen ancestor yang sama dan mengamati semuanya.
  • Fase pengambilan dijalankan sebelum fase target atau balon. Jadi, menambahkan pemroses di sana akan membantu memastikan pemroses tersebut berjalan sebelum kode lain dapat membatalkannya.

Rekomendasi developer untuk setiap negara bagian

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

Misalnya, tidak masuk akal untuk menampilkan notifikasi sementara kepada pengguna jika halaman berada dalam status tersembunyi. Meskipun contoh ini cukup jelas, ada rekomendasi lain yang tidak terlalu jelas yang layak diperhitungkan.

Negara Bagian Rekomendasi developer
Active

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

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

Passive

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

Saat halaman berubah dari aktif menjadi pasif, sebaiknya pertahankan status aplikasi yang belum disimpan.

Hidden

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

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

Ini berarti Anda harus memperlakukan status tersembunyi sebagai kemungkinan akhir untuk 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 terlihat oleh pengguna), dan harus menghentikan tugas apa pun yang tidak ingin dijalankan oleh pengguna di latar belakang.

Frozen

Dalam status frozen, tugas yang dapat dibekukan di task queue akan ditangguhkan hingga halaman tidak dibekukan lagi, yang mungkin tidak akan pernah terjadi (misalnya jika halaman dihapus).

Artinya, saat halaman berubah dari tersembunyi ke frozen, Anda harus menghentikan timer atau memutuskan koneksi apa pun yang, jika dibekukan, dapat memengaruhi tab terbuka lain di asal yang sama, atau memengaruhi kemampuan browser untuk menempatkan halaman dalam back/forward cache.

Secara khusus, penting bagi Anda untuk:

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 frozen kembali ke tersembunyi, Anda dapat membuka kembali koneksi yang tertutup atau memulai ulang polling yang Anda hentikan saat halaman pertama kali dibekukan.

Terminated

Biasanya, Anda tidak perlu melakukan tindakan apa pun jika halaman bertransisi ke status dihentikan.

Karena halaman yang dihapus muatannya sebagai akibat dari tindakan pengguna selalu melalui status tersembunyi sebelum memasuki status dihentikan, status tersembunyi adalah tempat logika akhir 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 kehilangan data.

Discarded

Status dibuang tidak dapat diamati oleh developer saat halaman dihapus. Hal ini karena halaman biasanya dihapus karena keterbatasan resource, dan mencairkan halaman hanya untuk memungkinkan skrip berjalan sebagai respons terhadap peristiwa penghapusan tidak mungkin dilakukan dalam sebagian besar kasus.

Dengan demikian, Anda harus mempersiapkan kemungkinan penghapusan perubahan dari hidden ke 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 pada tabel di atas adalah menggunakan PageLifecycle.js.

API siklus proses lama yang harus dihindari

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 aktif dalam banyak situasi penghapusan muatan yang umum, termasuk menutup tab dari pengalih tab di perangkat seluler atau menutup aplikasi browser dari pengalih aplikasi.

Oleh karena itu, sebaiknya selalu andalkan 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, hanya dengan adanya pengendali peristiwa unload yang terdaftar (melalui onunload atau addEventListener()), browser tidak akan dapat menempatkan halaman dalam back/forward cache untuk pemuatan back-forward dan maju yang lebih cepat.

Di semua browser modern, sebaiknya selalu gunakan peristiwa pagehide untuk mendeteksi kemungkinan penghapusan muatan halaman (alias status dihentikan), bukan peristiwa unload. Jika Anda perlu mendukung Internet Explorer versi 10 dan yang lebih lama, Anda harus menggunakan fitur 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 mirip dengan peristiwa unload, karena 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 mengaktifkan peristiwa beforeunload saat mencoba memasukkan halaman ke back-forward cache, yang berarti peristiwa tersebut tidak dapat diandalkan sebagai sinyal akhir sesi. Selain itu, beberapa browser (termasuk Chrome) memerlukan interaksi pengguna pada halaman sebelum mengizinkan peristiwa beforeunload diaktifkan, yang selanjutnya memengaruhi keandalannya.

Satu perbedaan antara beforeunload dan unload adalah bahwa ada penggunaan beforeunload yang sah. Misalnya, saat Anda ingin memperingatkan pengguna bahwa perubahan yang belum disimpan akan hilang jika mereka terus menghapus muatan 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 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();
    return (event.returnValue = '');
  }
});

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

const beforeUnloadListener = (event) => {
  event.preventDefault();
  return (event.returnValue = '');
};

// 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 "memuat"?

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

Halaman saya berfungsi penting saat disembunyikan. Bagaimana cara mencegahnya dibekukan atau dihapus?

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

Ada juga situasi yang berisiko bagi Chrome untuk menghapus halaman, seperti jika halaman berisi formulir dengan input pengguna yang belum dikirim, atau jika halaman memiliki pengendali beforeunload yang memberikan peringatan saat halaman menghapus muatan.

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

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

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

Apa itu back-forward cache?

Back/forward cache adalah istilah yang digunakan untuk menjelaskan pengoptimalan navigasi yang diterapkan beberapa browser sehingga penggunaan tombol kembali dan maju menjadi lebih cepat.

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

Untuk semua intent dan tujuan, pembekuan ini secara fungsional sama seperti yang dilakukan browser pembekuan untuk menghemat CPU/baterai. Oleh karena itu, pembekuan ini dianggap sebagai bagian dari status siklus proses frozen.

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 di task queue halaman akan ditangguhkan, yang berarti API asinkron dan berbasis callback seperti IndexedDB tidak dapat digunakan dengan andal.

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

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

  • Gunakan Penyimpanan Sesi: Penyimpanan Sesi bersifat 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. Pada 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 dibuang

Untuk menguji perilaku aplikasi Anda dalam keadaan beku dan dibuang, Anda dapat membuka chrome://discards untuk benar-benar membekukan atau menghapus tab yang terbuka.

Chrome Menghapus UI

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

Ringkasan

Developer yang ingin memanfaatkan resource sistem perangkat pengguna mereka harus mem-build aplikasi dengan mempertimbangkan status Siklus Proses Halaman. Halaman web harus tidak memakai resource sistem yang berlebihan dalam situasi yang tidak diharapkan pengguna

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