Membangun untuk browser modern dan meningkatkan secara progresif seperti tahun 2003
Dipublikasikan: 29 Juni 2020
Pada Maret 2003, Nick Finck dan Steve Champeon mengejutkan dunia desain web dengan konsep peningkatan progresif, strategi untuk desain web yang menekankan pemuatan konten halaman web inti terlebih dahulu, dan kemudian secara progresif menambahkan lapisan presentasi dan fitur yang lebih bernuansa dan ketat secara teknis di atas konten. Pada tahun 2003, peningkatan progresif adalah tentang penggunaan fitur CSS modern, JavaScript yang tidak mengganggu, dan bahkan hanya Scalable Vector Graphics. Peningkatan progresif pada tahun 2020 dan seterusnya adalah tentang penggunaan kemampuan browser modern.
JavaScript Modern
Berbicara tentang JavaScript, situasi dukungan browser untuk fitur JavaScript inti ES 2015 terbaru sangat baik. Standar baru ini mencakup promise,
modul, class, literal template, fungsi panah, let dan const,
parameter default, generator, penetapan destructuring, rest dan spread,
Map/Set, WeakMap/WeakSet, dan banyak lagi.
Semua didukung.
Fungsi asinkron, fitur ES 2017 dan salah satu favorit pribadi saya, dapat digunakan di semua browser utama.
Kata kunci async dan await memungkinkan perilaku berbasis promise asinkron
ditulis dalam gaya yang lebih bersih, sehingga tidak perlu mengonfigurasi rantai promise secara eksplisit.
Bahkan penambahan bahasa ES 2020 yang sangat baru seperti optional chaining dan nullish coalescing telah mendapatkan dukungan dengan sangat cepat. Dalam hal fitur JavaScript inti, tidak ada yang lebih baik dari yang ada saat ini.
Contoh:
const adventurer = {
name: 'Alice',
cat: {
name: 'Dinah',
},
};
console.log(adventurer.dog?.name);
// Expected output: undefined
console.log(0 ?? 42);
// Expected output: 0
Aplikasi contoh: Fugu Greetings
Untuk dokumen ini, saya bekerja dengan PWA, yang disebut Fugu Greetings (GitHub). Nama aplikasi ini merupakan penghormatan kepada Project Fugu 🐡, sebuah upaya untuk memberikan semua kemampuan aplikasi Android, iOS, dan desktop ke web. Anda dapat membaca selengkapnya project tersebut di halaman landing-nya.
Fugu Greetings adalah aplikasi menggambar yang memungkinkan Anda membuat kartu ucapan virtual, dan mengirimkannya kepada orang yang Anda cintai. Contoh ini menunjukkan konsep inti PWA. Aplikasi ini andal dan sepenuhnya dapat digunakan secara offline, jadi meskipun Anda tidak memiliki jaringan, Anda tetap dapat menggunakannya. Aplikasi ini juga Dapat Diinstal ke layar utama perangkat dan terintegrasi dengan lancar dengan sistem operasi sebagai aplikasi mandiri.
{i>Progressive enhancement <i}
Setelah ini selesai, sekarang saatnya membahas peningkatan progresif. Glosarium MDN Web Docs mendefinisikan konsep tersebut sebagai berikut:
Peningkatan progresif adalah filosofi desain yang menyediakan dasar konten dan fungsi penting kepada sebanyak mungkin pengguna, sekaligus memberikan pengalaman terbaik hanya kepada pengguna browser paling modern yang dapat menjalankan semua kode yang diperlukan.
Deteksi fitur umumnya digunakan untuk menentukan apakah browser dapat menangani fungsi yang lebih modern, sementara polyfill sering digunakan untuk menambahkan fitur yang tidak ada dengan JavaScript.
[…]
Peningkatan progresif adalah teknik berguna yang memungkinkan developer web berfokus pada pengembangan situs terbaik sekaligus memastikan situs tersebut berfungsi di beberapa agen pengguna yang tidak diketahui. Degradasi yang baik terkait, tetapi tidak sama dan sering kali dianggap berlawanan arah dengan peningkatan progresif. Pada kenyataannya, kedua pendekatan tersebut valid dan sering kali saling melengkapi.
Kontributor MDN
Memulai setiap kartu ucapan dari awal bisa sangat merepotkan.
Jadi, mengapa tidak memiliki fitur yang memungkinkan pengguna mengimpor gambar, dan memulai dari sana?
Dengan pendekatan tradisional, Anda akan menggunakan elemen
<input type=file>
untuk mewujudkannya.
Pertama, Anda akan membuat elemen, menetapkan type-nya ke 'file', dan menambahkan jenis MIME
ke properti accept, lalu "mengklik"-nya secara terprogram dan memantau
perubahan. Saat Anda memilih gambar, gambar tersebut akan langsung diimpor ke kanvas.
const importImage = async () => {
return new Promise((resolve) => {
const input = document.createElement('input');
input.type = 'file';
input.accept = 'image/*';
input.addEventListener('change', () => {
resolve(input.files[0]);
});
input.click();
});
};
Jika ada fitur impor, kemungkinan harus ada fitur ekspor
agar pengguna dapat menyimpan kartu ucapan mereka secara lokal.
Cara tradisional untuk menyimpan file adalah dengan membuat link anchor
dengan atribut download
dan dengan URL blob sebagai href-nya.
Anda juga akan "mengklik"-nya secara terprogram untuk memicu download,
dan, untuk mencegah kebocoran memori, semoga tidak lupa untuk mencabut URL objek blob.
const exportImage = async (blob) => {
const a = document.createElement('a');
a.download = 'fugu-greeting.png';
a.href = URL.createObjectURL(blob);
a.addEventListener('click', (e) => {
setTimeout(() => URL.revokeObjectURL(a.href), 30 * 1000);
});
a.click();
};
Tapi tunggu sebentar. Secara mental, Anda belum "mendownload" kartu ucapan, Anda telah "menyimpannya". Daripada menampilkan dialog "simpan" yang memungkinkan Anda memilih tempat untuk menyimpan file, browser telah mendownload kartu ucapan secara langsung tanpa interaksi pengguna dan menyimpannya langsung ke folder Download Anda. Ini tidak bagus.
Bagaimana jika ada cara yang lebih baik? Bagaimana jika Anda dapat membuka file lokal, mengeditnya, lalu menyimpan modifikasi, baik ke file baru, atau kembali ke file asli yang awalnya Anda buka? Ternyata ada. File System Access API memungkinkan Anda membuka dan membuat file serta direktori, juga memodifikasi dan menyimpannya .
Jadi, bagaimana cara mendeteksi fitur API?
File System Access API menampilkan metode baru window.chooseFileSystemEntries().
Oleh karena itu, saya perlu memuat modul impor dan ekspor yang berbeda secara bersyarat, bergantung pada apakah metode ini tersedia atau tidak.
const loadImportAndExport = () => {
if ('chooseFileSystemEntries' in window) {
Promise.all([
import('./import_image.mjs'),
import('./export_image.mjs'),
]);
} else {
Promise.all([
import('./import_image_legacy.mjs'),
import('./export_image_legacy.mjs'),
]);
}
};
Namun, sebelum membahas detail File System Access API, izinkan saya menyoroti pola peningkatan progresif di sini. Di browser yang tidak mendukung File System Access API, saya memuat skrip lama.
Namun, di Chrome, browser yang mendukung API, hanya skrip baru yang dimuat.
Hal ini dapat dilakukan dengan mudah berkat
import() dinamis, yang didukung oleh semua browser modern.
Seperti yang saya katakan sebelumnya, rumputnya cukup hijau akhir-akhir ini.
File System Access API
Jadi, setelah saya membahas hal ini, sekarang saatnya melihat penerapan sebenarnya berdasarkan File System Access API.
Untuk mengimpor gambar, saya memanggil window.chooseFileSystemEntries()
dan meneruskan properti accepts yang menyatakan bahwa saya menginginkan file gambar.
Ekstensi file dan jenis MIME didukung.
Hal ini akan menghasilkan handle file, yang darinya saya bisa mendapatkan file sebenarnya dengan memanggil getFile().
const importImage = async () => {
try {
const handle = await window.chooseFileSystemEntries({
accepts: [
{
description: 'Image files',
mimeTypes: ['image/*'],
extensions: ['jpg', 'jpeg', 'png', 'webp', 'svg'],
},
],
});
return handle.getFile();
} catch (err) {
console.error(err.name, err.message);
}
};
Mengekspor gambar hampir sama, tetapi kali ini
saya perlu meneruskan parameter jenis 'save-file' ke metode chooseFileSystemEntries().
Dari sini, saya mendapatkan dialog penyimpanan file.
Dengan file terbuka, hal ini tidak diperlukan karena 'open-file' adalah default.
Saya menetapkan parameter accepts dengan cara yang sama seperti sebelumnya, tetapi kali ini hanya terbatas pada gambar PNG.
Sekali lagi saya mendapatkan handle file, tetapi alih-alih mendapatkan file, kali ini saya membuat stream yang dapat ditulis dengan memanggil createWritable().
Selanjutnya, saya menulis blob, yang merupakan gambar kartu ucapan saya, ke file.
Terakhir, saya menutup aliran yang dapat ditulis.
Semua hal bisa gagal: Disk bisa kehabisan ruang, bisa terjadi error penulisan atau pembacaan, atau mungkin pengguna membatalkan dialog file.
Itulah sebabnya saya selalu membungkus panggilan dalam pernyataan try...catch.
const exportImage = async (blob) => {
try {
const handle = await window.chooseFileSystemEntries({
type: 'save-file',
accepts: [
{
description: 'Image file',
extensions: ['png'],
mimeTypes: ['image/png'],
},
],
});
const writable = await handle.createWritable();
await writable.write(blob);
await writable.close();
} catch (err) {
console.error(err.name, err.message);
}
};
Dengan peningkatan progresif menggunakan File System Access API, saya dapat membuka file seperti sebelumnya. File yang diimpor digambar langsung ke kanvas. Saya dapat melakukan pengeditan dan akhirnya menyimpannya dengan dialog penyimpanan yang sebenarnya, tempat saya dapat memilih nama dan lokasi penyimpanan file. Sekarang file siap diabadikan.
Web Share API dan Web Share Target API

Selain menyimpannya selamanya, mungkin saya ingin membagikan kartu ucapan saya. Hal ini dapat dilakukan dengan Web Share API dan Web Share Target API. Sistem operasi seluler, dan baru-baru ini desktop, telah mendapatkan mekanisme berbagi bawaan.
Misalnya, sheet berbagi Safari desktop di macOS dipicu saat pengguna mengklik Bagikan Artikel di blog saya. Anda dapat membagikan link artikel kepada teman menggunakan aplikasi Pesan macOS.
Untuk melakukannya, saya memanggil navigator.share() dan meneruskan title, text, dan url opsional dalam sebuah objek.
Namun, bagaimana jika saya ingin melampirkan gambar? Level 1 Web Share API belum mendukung hal ini.
Kabar baiknya, Web Share Level 2 telah menambahkan kemampuan berbagi file.
try {
await navigator.share({
title: 'Check out this article:',
text: `"${document.title}" by @tomayac:`,
url: document.querySelector('link[rel=canonical]').href,
});
} catch (err) {
console.warn(err.name, err.message);
}
Izinkan saya menunjukkan cara membuatnya berfungsi dengan aplikasi kartu ucapan Fugu.
Pertama, saya perlu menyiapkan objek data dengan array files yang terdiri dari satu blob, lalu
title dan text. Selanjutnya, sebagai praktik terbaik, saya menggunakan metode navigator.canShare() baru yang melakukan
apa yang disarankan namanya:
Metode ini memberi tahu saya apakah objek data yang saya coba bagikan secara teknis dapat dibagikan oleh browser.
Jika navigator.canShare() memberi tahu saya bahwa data dapat dibagikan, saya siap
memanggil navigator.share() seperti sebelumnya.
Karena semuanya bisa gagal, saya kembali menggunakan blok try...catch.
const share = async (title, text, blob) => {
const data = {
files: [
new File([blob], 'fugu-greeting.png', {
type: blob.type,
}),
],
title: title,
text: text,
};
try {
if (!(navigator.canShare(data))) {
throw new Error("Can't share data.", data);
}
await navigator.share(data);
} catch (err) {
console.error(err.name, err.message);
}
};
Seperti sebelumnya, saya menggunakan progressive enhancement.
Jika 'share' dan 'canShare' ada di objek navigator, barulah saya melanjutkan dan
memuat share.mjs menggunakan import() dinamis.
Di browser seperti Safari seluler yang hanya memenuhi salah satu dari dua kondisi, saya tidak memuat
fungsionalitas.
const loadShare = () => {
if ('share' in navigator && 'canShare' in navigator) {
import('./share.mjs');
}
};
Di Fugu Greetings, jika saya mengetuk tombol Bagikan di browser yang mendukung seperti Chrome di Android, lembar berbagi bawaan akan terbuka. Misalnya, saya dapat memilih Gmail, dan widget pembuat email akan muncul dengan gambar terlampir.
Contact Picker API
Selanjutnya, saya ingin membahas kontak, yang berarti buku alamat perangkat atau aplikasi pengelola kontak. Saat Anda menulis kartu ucapan, mungkin tidak selalu mudah untuk menulis nama seseorang dengan benar. Misalnya, saya memiliki teman bernama Sergey yang lebih suka namanya dieja dalam huruf Kiril. Saya menggunakan keyboard QWERTZ Jerman dan tidak tahu cara mengetik nama mereka. Ini adalah masalah yang dapat diselesaikan oleh Contact Picker API. Karena saya menyimpan teman saya di aplikasi kontak ponsel saya, saya dapat mengakses kontak saya dari web menggunakan Contacts Picker API.
Pertama, saya perlu menentukan daftar properti yang ingin saya akses.
Dalam hal ini, saya hanya ingin nama,
tetapi untuk kasus penggunaan lain, saya mungkin tertarik dengan nomor telepon, email, ikon avatar, atau alamat fisik.
Selanjutnya, saya mengonfigurasi objek options dan menyetel multiple ke true, sehingga saya dapat memilih lebih dari satu entri.
Terakhir, saya dapat memanggil navigator.contacts.select(), yang menampilkan properti
yang ideal untuk kontak yang dipilih pengguna.
const getContacts = async () => {
const properties = ['name'];
const options = { multiple: true };
try {
return await navigator.contacts.select(properties, options);
} catch (err) {
console.error(err.name, err.message);
}
};
Dan sekarang Anda mungkin telah mempelajari polanya: Saya hanya memuat file saat API benar-benar didukung.
if ('contacts' in navigator) {
import('./contacts.mjs');
}
Di Fugu Greeting, saat saya mengetuk tombol Kontak dan memilih dua sahabat saya, Сергей Михайлович Брин dan 劳伦斯·爱德华·"拉里"·佩奇, Anda dapat melihat bagaimana pemilih kontak dibatasi hanya untuk menampilkan nama mereka, tetapi tidak menampilkan alamat email, atau informasi lain seperti nomor telepon mereka. Kemudian, nama mereka digambar di kartu ucapan saya.
Asynchronous Clipboard API
Selanjutnya adalah menyalin dan menempel. Salah satu operasi favorit kami sebagai developer software adalah salin dan tempel. Sebagai penulis kartu ucapan, terkadang saya ingin melakukan hal yang sama. Saya mungkin ingin menempelkan gambar ke kartu ucapan yang sedang saya kerjakan, atau menyalin kartu ucapan saya agar saya dapat terus mengeditnya dari tempat lain. Async Clipboard API, mendukung teks dan gambar. Izinkan saya memandu Anda tentang cara menambahkan dukungan salin dan tempel ke aplikasi Fugu Greetings.
Untuk menyalin sesuatu ke papan klip sistem, saya perlu menulis ke papan klip tersebut.
Metode navigator.clipboard.write() mengambil array item papan klip sebagai
parameter.
Setiap item papan klip pada dasarnya adalah objek dengan blob sebagai nilai, dan jenis blob
sebagai kunci.
const copy = async (blob) => {
try {
await navigator.clipboard.write([
new ClipboardItem({
[blob.type]: blob,
}),
]);
} catch (err) {
console.error(err.name, err.message);
}
};
Untuk menempelkan, saya perlu melakukan loop pada item papan klip yang saya dapatkan dengan memanggil
navigator.clipboard.read().
Alasannya adalah karena beberapa item papan klip mungkin ada di papan klip dalam representasi yang berbeda.
Setiap item papan klip memiliki kolom types yang memberi tahu saya jenis MIME sumber daya yang tersedia.
Saya memanggil metode getType() item papan klip, dengan meneruskan
jenis MIME yang saya peroleh sebelumnya.
const paste = async () => {
try {
const clipboardItems = await navigator.clipboard.read();
for (const clipboardItem of clipboardItems) {
try {
for (const type of clipboardItem.types) {
const blob = await clipboardItem.getType(type);
return blob;
}
} catch (err) {
console.error(err.name, err.message);
}
}
} catch (err) {
console.error(err.name, err.message);
}
};
Dan hampir tidak perlu dikatakan lagi sekarang. Saya hanya melakukannya di browser yang mendukung.
if ('clipboard' in navigator && 'write' in navigator.clipboard) {
import('./clipboard.mjs');
}
Jadi, bagaimana cara kerjanya dalam praktiknya? Saya membuka gambar di aplikasi Pratinjau macOS dan menyalinnya ke papan klip. Saat saya mengklik Tempel, aplikasi Fugu Greetings akan menanyakan apakah saya ingin mengizinkan aplikasi melihat teks dan gambar di papan klip.
Terakhir, setelah menyetujui izin, gambar akan ditempelkan ke dalam aplikasi. Cara sebaliknya juga berfungsi. Izinkan saya menyalin kartu ucapan ke papan klip. Saat saya membuka Pratinjau, lalu mengklik File, lalu Baru dari Papan Klip, kartu ucapan akan ditempelkan ke gambar baru tanpa judul.
Badging API
API lain yang berguna adalah Badging API.
Sebagai PWA yang dapat diinstal, Fugu Greetings tentu saja memiliki ikon aplikasi
yang dapat ditempatkan pengguna di dok aplikasi atau layar utama.
Cara yang menyenangkan untuk mendemonstrasikan API adalah dengan menggunakannya di Fugu Greetings, sebagai penghitung goresan pena.
Saya telah menambahkan pemroses peristiwa yang menambahkan penghitung goresan pena setiap kali peristiwa pointerdown terjadi, lalu menetapkan badge ikon yang diperbarui.
Setiap kali kanvas dibersihkan, penghitung akan direset, dan badge akan dihapus.
let strokes = 0;
canvas.addEventListener('pointerdown', () => {
navigator.setAppBadge(++strokes);
});
clearButton.addEventListener('click', () => {
strokes = 0;
navigator.setAppBadge(strokes);
});
Fitur ini adalah peningkatan progresif, sehingga logika pemuatan seperti biasa.
if ('setAppBadge' in navigator) {
import('./badge.mjs');
}
Dalam contoh ini, saya telah menggambar angka satu hingga tujuh, menggunakan satu goresan pena per angka. Penghitung badge pada ikon kini berada di angka tujuh.
Periodic Background Sync API
Ingin memulai setiap hari dengan sesuatu yang baru? Fitur menarik dari aplikasi Fugu Greetings adalah aplikasi ini dapat menginspirasi Anda setiap pagi dengan gambar latar baru untuk memulai kartu ucapan Anda. Aplikasi menggunakan Periodic Background Sync API untuk mencapai hal ini.
Langkah pertama adalah mendaftarkan peristiwa sinkronisasi berkala dalam pendaftaran pekerja layanan. Aplikasi ini memproses tag sinkronisasi yang disebut 'image-of-the-day'
dan memiliki interval minimum satu hari,
sehingga pengguna bisa mendapatkan gambar latar baru setiap 24 jam.
const registerPeriodicBackgroundSync = async () => {
const registration = await navigator.serviceWorker.ready;
try {
registration.periodicSync.register('image-of-the-day-sync', {
// An interval of one day.
minInterval: 24 * 60 * 60 * 1000,
});
} catch (err) {
console.error(err.name, err.message);
}
};
Langkah kedua adalah memproses peristiwa periodicsync di pekerja layanan.
Jika tag peristiwa adalah 'image-of-the-day', yaitu yang terdaftar sebelumnya,
gambar hari ini diambil dengan fungsi getImageOfTheDay(),
dan hasilnya disebarkan ke semua klien, sehingga mereka dapat memperbarui kanvas dan
cache-nya.
self.addEventListener('periodicsync', (syncEvent) => {
if (syncEvent.tag === 'image-of-the-day-sync') {
syncEvent.waitUntil(
(async () => {
const blob = await getImageOfTheDay();
const clients = await self.clients.matchAll();
clients.forEach((client) => {
client.postMessage({
image: blob,
});
});
})()
);
}
});
Sekali lagi, ini benar-benar peningkatan progresif, sehingga kode hanya dimuat saat
API didukung oleh browser.
Hal ini berlaku untuk kode klien dan kode pekerja layanan.
Di browser yang tidak mendukung, keduanya tidak dimuat.
Perhatikan bagaimana di pekerja layanan, alih-alih import() dinamis
(yang belum didukung dalam konteks pekerja layanan),
saya menggunakan
importScripts() klasik.
// In the client:
const registration = await navigator.serviceWorker.ready;
if (registration && 'periodicSync' in registration) {
import('./periodic_background_sync.mjs');
}
// In the service worker:
if ('periodicSync' in self.registration) {
importScripts('./image_of_the_day.mjs');
}
Di Fugu Greetings, menekan tombol Wallpaper akan menampilkan gambar kartu ucapan harian yang diperbarui setiap hari dengan Periodic Background Sync API.
Notification Triggers API
Terkadang, meskipun sudah memiliki banyak inspirasi, Anda memerlukan dorongan untuk menyelesaikan kartu ucapan yang sudah dimulai. Fitur ini diaktifkan oleh Notification Triggers API. Sebagai pengguna, saya dapat memasukkan waktu saat saya ingin diingatkan untuk menyelesaikan kartu ucapan. Saat waktunya tiba, saya akan mendapatkan notifikasi bahwa kartu ucapan saya sudah tersedia.
Setelah meminta waktu target,
aplikasi menjadwalkan notifikasi dengan showTrigger.
Hal ini dapat berupa TimestampTrigger dengan tanggal target yang dipilih sebelumnya.
Notifikasi pengingat akan dipicu secara lokal, tidak memerlukan sisi jaringan atau server.
const targetDate = promptTargetDate();
if (targetDate) {
const registration = await navigator.serviceWorker.ready;
registration.showNotification('Reminder', {
tag: 'reminder',
body: "It's time to finish your greeting card!",
showTrigger: new TimestampTrigger(targetDate),
});
}
Seperti semua hal lain yang telah saya tunjukkan sejauh ini, ini adalah peningkatan progresif, sehingga kode hanya dimuat secara bersyarat.
if ('Notification' in window && 'showTrigger' in Notification.prototype) {
import('./notification_triggers.mjs');
}
Saat saya mencentang kotak Pengingat di Fugu Greetings, muncul perintah yang menanyakan kapan saya ingin diingatkan untuk menyelesaikan kartu ucapan.
Saat notifikasi terjadwal dipicu di Fugu Greetings, notifikasi tersebut ditampilkan seperti notifikasi lainnya, tetapi seperti yang saya tulis sebelumnya, notifikasi tersebut tidak memerlukan koneksi jaringan.
Wake Lock API
Saya juga ingin menyertakan Wake Lock API. Terkadang, Anda hanya perlu menatap layar cukup lama hingga inspirasi datang. Kemungkinan terburuk yang dapat terjadi adalah layar akan mati. Wake Lock API dapat mencegah hal ini terjadi.
Langkah pertama adalah mendapatkan kunci aktif dengan navigator.wakelock.request method().
Saya meneruskan string 'screen' untuk mendapatkan penguncian layar saat aktif.
Kemudian, saya menambahkan pemroses peristiwa untuk diberi tahu saat kunci tetap aktif dilepaskan.
Hal ini dapat terjadi, misalnya, saat visibilitas tab berubah.
Jika hal ini terjadi, saya dapat memperoleh kembali kunci tetap aktif saat tab terlihat lagi.
let wakeLock = null;
const requestWakeLock = async () => {
wakeLock = await navigator.wakeLock.request('screen');
wakeLock.addEventListener('release', () => {
console.log('Wake Lock was released');
});
console.log('Wake Lock is active');
};
const handleVisibilityChange = () => {
if (wakeLock !== null && document.visibilityState === 'visible') {
requestWakeLock();
}
};
document.addEventListener('visibilitychange', handleVisibilityChange);
document.addEventListener('fullscreenchange', handleVisibilityChange);
Ya, ini adalah peningkatan progresif, jadi saya hanya perlu memuatnya saat browser mendukung API.
if ('wakeLock' in navigator && 'request' in navigator.wakeLock) {
import('./wake_lock.mjs');
}
Di Fugu Greetings, ada kotak centang Insomnia yang, jika dicentang, akan membuat layar tetap aktif.
Idle Detection API
Terkadang, meskipun Anda menatap layar selama berjam-jam, Anda tidak akan mendapatkan ide sedikit pun tentang apa yang harus dilakukan dengan kartu ucapan Anda. Idle Detection API memungkinkan aplikasi mendeteksi waktu tidak aktif pengguna. Jika pengguna tidak beraktivitas terlalu lama, aplikasi akan direset ke status awal dan menghapus kanvas. API ini dibatasi oleh izin notifikasi, karena banyak kasus penggunaan deteksi tidak ada aktivitas di produksi terkait dengan notifikasi, misalnya, hanya mengirim notifikasi ke perangkat yang sedang digunakan pengguna secara aktif.
Setelah memastikan bahwa izin notifikasi diberikan, saya kemudian membuat instance detektor tidak ada aktivitas. Saya mendaftarkan pemroses peristiwa yang memproses perubahan status tidak ada aktivitas, yang mencakup status pengguna dan layar. Pengguna dapat aktif atau tidak aktif, dan layar dapat dibuka kuncinya atau dikunci. Jika pengguna tidak aktif, kanvas akan dibersihkan. Saya memberi detektor tidak ada aktivitas batas waktu 60 detik.
const idleDetector = new IdleDetector();
idleDetector.addEventListener('change', () => {
const userState = idleDetector.userState;
const screenState = idleDetector.screenState;
console.log(`Idle change: ${userState}, ${screenState}.`);
if (userState === 'idle') {
clearCanvas();
}
});
await idleDetector.start({
threshold: 60000,
signal,
});
Seperti biasa, saya hanya memuat kode ini saat browser mendukungnya.
if ('IdleDetector' in window) {
import('./idle_detection.mjs');
}
Di aplikasi Fugu Greetings, kanvas akan dibersihkan saat kotak centang Ephemeral dicentang dan pengguna menganggur terlalu lama.
Penutup
Fiuh, perjalanan yang melelahkan. Begitu banyak API dalam satu aplikasi contoh. Selain itu, ingatlah bahwa saya tidak pernah membuat pengguna membayar biaya download untuk fitur yang tidak didukung oleh browser mereka. Dengan menggunakan peningkatan progresif, saya memastikan hanya kode yang relevan yang dimuat. Dan karena dengan HTTP/2, permintaan tidak mahal, pola ini akan berfungsi dengan baik untuk banyak aplikasi, meskipun Anda mungkin ingin mempertimbangkan bundler untuk aplikasi yang sangat besar.
Aplikasi mungkin terlihat sedikit berbeda di setiap browser karena tidak semua platform mendukung semua fitur, tetapi fungsi intinya selalu ada—ditingkatkan secara progresif sesuai dengan kemampuan browser tertentu. Kemampuan ini dapat berubah bahkan di browser yang sama, bergantung pada apakah aplikasi berjalan sebagai aplikasi yang diinstal atau di tab browser.
Anda dapat membuat fork Fugu di GitHub.
Tim Chromium berupaya keras untuk membuat Fugu API tingkat lanjut menjadi lebih baik. Dengan menerapkan peningkatan progresif saat membangun aplikasi, saya memastikan semua orang mendapatkan pengalaman dasar yang baik dan solid, tetapi orang yang menggunakan browser yang mendukung lebih banyak API platform Web akan mendapatkan pengalaman yang lebih baik. Kami menantikan untuk melihat apa yang Anda lakukan dengan peningkatan progresif di aplikasi Anda.
Ucapan terima kasih
Saya berterima kasih kepada Christian Liebel dan
Hemanth HM yang telah berkontribusi pada Fugu Greetings.
Dokumen ini ditinjau oleh Joe Medley dan
Kayce Basques.
Jake Archibald membantu saya mengetahui situasi
dengan import() dinamis dalam konteks pekerja layanan.