Penyimpanan KV - Modul Bawaan Pertama Web

Vendor browser dan pakar performa web telah mengatakan selama lebih dari sepuluh tahun terakhir bahwa localStorage lambat, dan developer web harus berhenti menggunakannya.

Sejujurnya, orang yang mengatakan hal ini tidak salah. localStorage adalah API sinkron yang memblokir thread utama, dan setiap kali Anda mengaksesnya, Anda berpotensi mencegah halaman menjadi interaktif.

Masalahnya adalah API localStorage sangat sederhana dan menarik, dan satu-satunya alternatif asinkron untuk localStorage adalah IndexedDB, yang (mari kita hadapi) tidak dikenal karena kemudahan penggunaan atau API yang mudah digunakan.

Jadi, developer hanya memiliki pilihan antara sesuatu yang sulit digunakan dan sesuatu yang buruk untuk performa. Meskipun ada library yang menawarkan kesederhanaan localStorage API sekaligus menggunakan API penyimpanan asinkron di belakang layar, menyertakan salah satu library tersebut di aplikasi Anda akan memiliki biaya ukuran file dan dapat mengurangi anggaran performa Anda.

Namun, bagaimana jika Anda bisa mendapatkan performa API penyimpanan asinkron dengan kesederhanaan localStorage API, tanpa harus membayar biaya ukuran file?

Mungkin dalam waktu dekat. Chrome sedang bereksperimen dengan fitur baru yang dikenal sebagai modul bawaan, dan yang pertama yang kami rencanakan untuk dirilis adalah modul penyimpanan kunci/nilai asinkron yang disebut Penyimpanan KV.

Namun, sebelum membahas detail modul KV Storage, izinkan saya menjelaskan apa yang saya maksud dengan modul bawaan.

Apa yang dimaksud dengan modul bawaan?

Modul bawaan sama seperti modul JavaScript biasa, tetapi tidak perlu didownload karena disertakan dengan browser.

Seperti API web tradisional, modul bawaan harus melalui proses standarisasi. Setiap modul akan memiliki spesifikasinya sendiri yang memerlukan peninjauan desain dan tanda dukungan positif dari developer web dan vendor browser lainnya sebelum dapat dikirim. (Di Chrome, modul bawaan akan mengikuti proses peluncuran yang sama dengan yang kita gunakan untuk mengimplementasikan dan mengirimkan semua API baru.)

Tidak seperti API web tradisional, modul bawaan tidak ditampilkan di cakupan global — modul hanya tersedia melalui impor.

Tidak mengekspos modul bawaan secara global memiliki banyak keuntungan: modul tidak akan menambahkan overhead apa pun untuk memulai konteks runtime JavaScript baru (misalnya tab, pekerja, atau pekerja layanan baru), dan modul tidak akan menggunakan memori atau CPU kecuali modul tersebut benar-benar diimpor. Selain itu, variabel ini tidak berisiko mengalami konflik penamaan dengan variabel lain yang ditentukan dalam kode Anda.

Untuk mengimpor modul bawaan, Anda menggunakan awalan std:, diikuti dengan ID modul bawaan. Misalnya, di browser yang didukung, Anda dapat mengimpor modul KV Storage dengan kode berikut (lihat di bawah untuk cara menggunakan polyfill KV Storage di browser yang tidak didukung):

import storage, {StorageArea} from 'std:kv-storage';

Modul Penyimpanan KV

Modul KV Storage memiliki kesederhanaan yang mirip dengan localStorage API, tetapi bentuknya sebenarnya lebih mirip dengan Map JavaScript. Sebagai ganti getItem(), setItem(), dan removeItem(), versi ini memiliki get(), set(), dan delete(). Class ini juga memiliki metode seperti peta lainnya yang tidak tersedia untuk localStorage, seperti keys(), values(), dan entries(), dan seperti Map, kuncinya tidak harus berupa string. Jenis ini dapat berupa jenis serialisasi terstruktur apa pun.

Tidak seperti Map, semua metode KV Storage menampilkan promise atau iterator asinkron (karena titik utama modul ini adalah tidak sinkron, berbeda dengan localStorage). Untuk melihat API lengkap secara mendetail, Anda dapat melihat spesifikasi.

Seperti yang mungkin Anda perhatikan dari contoh kode di atas, modul KV Storage memiliki satu ekspor default storage dan satu ekspor bernama StorageArea.

storage adalah instance class StorageArea dengan nama 'default', dan ini adalah yang paling sering digunakan developer dalam kode aplikasi mereka. Class StorageArea disediakan untuk kasus saat isolasi tambahan diperlukan (misalnya, library pihak ketiga yang menyimpan data dan ingin menghindari konflik dengan data yang disimpan melalui instance storage default). Data StorageArea disimpan di database IndexedDB dengan nama kv-storage:${name}, dengan nama adalah nama instance StorageArea.

Berikut adalah contoh cara menggunakan modul Penyimpanan KV dalam kode Anda:

import storage from 'std:kv-storage';

const main = async () => {
  const oldPreferences = await storage.get('preferences');

  document.querySelector('form').addEventListener('submit', async () => {
    const newPreferences = Object.assign({}, oldPreferences, {
      // Updated preferences go here...
    });

    await storage.set('preferences', newPreferences);
  });
};

main();

Bagaimana jika browser tidak mendukung modul bawaan?

Jika sudah terbiasa menggunakan modul JavaScript native di browser, Anda mungkin mengetahui bahwa (setidaknya hingga saat ini) mengimpor apa pun selain URL akan menghasilkan error. Selain itu, std:kv-storage bukan URL yang valid.

Jadi, muncul pertanyaan: apakah kita harus menunggu hingga semua browser mendukung modul bawaan sebelum dapat menggunakannya dalam kode? Untungnya, jawabannya adalah tidak.

Anda sebenarnya dapat menggunakan modul bawaan segera setelah satu browser mendukungnya berkat bantuan fitur lain yang sedang kami jadikan eksperimen dan disebut import maps.

Mengimpor peta

Peta impor pada dasarnya adalah mekanisme yang dapat digunakan developer untuk membuat alias identitas impor ke satu atau beberapa ID alternatif.

Hal ini sangat bermanfaat karena memberi Anda cara untuk mengubah (saat runtime) cara browser menyelesaikan ID impor tertentu di seluruh aplikasi Anda.

Dalam kasus modul bawaan, hal ini memungkinkan Anda mereferensikan polyfill modul dalam kode aplikasi, tetapi browser yang mendukung modul bawaan dapat memuat versi tersebut.

Berikut cara mendeklarasikan peta impor agar berfungsi dengan modul Penyimpanan KV:

<!-- The import map is inlined into your page -->
<script type="importmap">
{
  "imports": {
    "/path/to/kv-storage-polyfill.mjs": [
      "std:kv-storage",
      "/path/to/kv-storage-polyfill.mjs"
    ]
  }
}
</script>

<!-- Then any module scripts with import statements use the above map -->
<script type="module">
  import storage from '/path/to/kv-storage-polyfill.mjs';

  // Use `storage` ...
</script>

Poin utama dalam kode di atas adalah URL /path/to/kv-storage-polyfill.mjs dipetakan ke dua resource yang berbeda: std:kv-storage, lalu URL asli lagi, /path/to/kv-storage-polyfill.mjs.

Jadi, saat browser menemukan pernyataan impor yang mereferensikan URL tersebut (/path/to/kv-storage-polyfill.mjs), browser akan mencoba memuat std:kv-storage terlebih dahulu, dan jika tidak dapat, browser akan kembali memuat /path/to/kv-storage-polyfill.mjs.

Sekali lagi, keajaibannya adalah browser tidak perlu mendukung peta impor atau modul bawaan agar teknik ini berfungsi karena URL yang diteruskan ke pernyataan impor adalah URL untuk polyfill. Polyfill sebenarnya bukan penggantian, tetapi merupakan default. Modul bawaan adalah peningkatan progresif.

Bagaimana dengan browser yang sama sekali tidak mendukung modul?

Untuk menggunakan peta impor guna memuat modul bawaan secara kondisional, Anda harus menggunakan pernyataan import, yang juga berarti Anda harus menggunakan skrip modul, yaitu <script type="module">.

Saat ini, lebih dari 80% browser mendukung modul, dan untuk browser yang tidak mendukung modul, Anda dapat menggunakan teknik module/nomodule untuk menayangkan paket lama. Perhatikan bahwa saat membuat build nomodule, Anda harus menyertakan semua polyfill karena Anda tahu pasti bahwa browser yang tidak mendukung modul pasti tidak akan mendukung modul bawaan.

Demo KV Storage

Untuk mengilustrasikan bahwa Anda dapat menggunakan modul bawaan sekaligus masih mendukung browser lama, saya telah menyusun demo yang menggabungkan semua teknik yang dijelaskan di atas dan berjalan di semua browser saat ini:

  • Browser yang mendukung modul, mengimpor peta, dan modul bawaan tidak memuat kode yang tidak diperlukan.
  • Browser yang mendukung modul dan mengimpor peta, tetapi tidak mendukung modul bawaan, akan memuat polyfill Penyimpanan KV (melalui loader modul browser).
  • Browser yang mendukung modul, tetapi tidak mendukung peta impor juga memuat polyfill Penyimpanan KV (melalui loader modul browser).
  • Browser yang sama sekali tidak mendukung modul akan mendapatkan polyfill KV Storage dalam paket lama (dimuat melalui <script nomodule>).

Demo dihosting di Glitch, sehingga Anda dapat melihat sumbernya. Saya juga memiliki penjelasan mendetail tentang penerapannya di README. Silakan lihat jika Anda ingin tahu cara membuatnya.

Untuk benar-benar melihat cara kerja modul bawaan native, Anda harus memuat demo di Chrome 74 atau yang lebih baru dengan flag fitur platform web eksperimental diaktifkan (chrome://flags/#enable-experimental-web-platform-features).

Anda dapat memverifikasi bahwa modul bawaan sedang dimuat karena Anda tidak akan melihat skrip polyfill di panel sumber di DevTools; sebagai gantinya, Anda akan melihat versi modul bawaan (fakta menarik: Anda sebenarnya dapat memeriksa kode sumber modul atau bahkan menempatkan titik henti sementara di dalamnya):

Sumber modul KV Storage di Chrome DevTools

Harap berikan masukan

Pengantar ini seharusnya telah memberi Anda gambaran tentang hal yang mungkin dilakukan dengan modul bawaan. Dan semoga Anda bersemangat. Kami sangat ingin developer mencoba modul KV Storage (serta semua fitur baru yang dibahas di sini) dan memberi kami masukan.

Berikut adalah link GitHub tempat Anda dapat memberi kami masukan untuk setiap fitur yang disebutkan dalam artikel ini:

Jika situs Anda saat ini menggunakan localStorage, Anda harus mencoba beralih ke KV Storage API untuk melihat apakah API tersebut memenuhi semua kebutuhan Anda. Selain itu, jika mendaftar ke uji coba origin KV Storage, Anda dapat men-deploy fitur ini sekarang. Semua pengguna akan mendapatkan manfaat dari performa penyimpanan yang lebih baik, dan pengguna Chrome 74+ tidak perlu membayar biaya download tambahan.