KV Storage – pierwszy wbudowany moduł w sieci

Przez większość ostatniej dekady dostawcy przeglądarek i eksperci ds. wydajności stron internetowych twierdzili, że localStorage jest wolny, a programiści powinni przestać go używać.

Prawdę mówiąc, osoby, które tak mówią, nie mają racji. localStorage to synchroniczny interfejs API, który blokuje wątek główny. Każdy dostęp do niego może potencjalnie uniemożliwić interaktywność strony.

Problem polega na tym, że interfejs API localStorage jest bardzo prosty, a jedyną asynchroniczną alternatywą dla localStorage jest IndexedDB, który (powiedzmy sobie szczerze) nie jest znany z łatwości użycia ani przyjaznego interfejsu API.

Deweloperzy mają więc do wyboru: coś trudnego w użyciu lub coś, co ma negatywny wpływ na wydajność. Chociaż istnieją biblioteki, które oferują prostotę interfejsu localStorage API, a w tle korzystają z asynchronicznych interfejsów API pamięci masowej, dodanie jednej z tych bibliotek do aplikacji wiąże się z większym rozmiarem pliku i może spożytkować budżet wydajności.

A co, jeśli można by uzyskać wydajność asynchronicznego interfejsu API pamięci masowej przy prostocie interfejsu API localStorage, bez konieczności płacenia za rozmiar pliku?

Wkrótce może się pojawić. W Chrome eksperymentujemy z nową funkcją o nazwie wbudowane moduły. Pierwszym z nich, który planujemy wprowadzić, jest asynchroniczny moduł przechowywania kluczy i wartości o nazwie KV Storage.

Zanim jednak omówię szczegóły modułu KV Storage, wyjaśnię, co mam na myśli, gdy mówię o wbudowanych modułach.

Co to są wbudowane moduły?

Moduły wbudowane są takie same jak zwykłe moduły JavaScriptu, z tym że nie trzeba ich pobierać, ponieważ są dostarczane z przeglądarką.

Podobnie jak tradycyjne interfejsy API, wbudowane moduły muszą przejść proces standaryzacji. Każdy z nich ma swoją specyfikację, która wymaga sprawdzenia projektu i pozytywnych sygnałów o wsparciu zarówno ze strony programistów stron internetowych, jak i innych dostawców przeglądarek, zanim moduł będzie można udostępnić. W Chrome wbudowane moduły będą stosować ten sam proces uruchamiania, który wykorzystujemy do implementowania i wysyłania wszystkich nowych interfejsów API.

W odróżnieniu od tradycyjnych interfejsów API w internecie wbudowane moduły nie są dostępne globalnie – są dostępne tylko za pomocą importów.

Nieujawnienie wbudowanych modułów na całym świecie ma wiele zalet: nie będą one zwiększać obciążenia związanego z uruchamianiem nowego kontekstu środowiska uruchomieniowego JavaScript (np. nowej karty, workera lub usługi), a także nie będą zużywać pamięci ani procesora, chyba że zostaną zaimportowane. Poza tym nie ma ryzyka kolizji nazw z innymi zmiennymi zdefiniowanymi w Twoim kodzie.

Aby zaimportować wbudowany moduł, użyj prefiksu std:, a następnie identyfikatora wbudowanego modułu. Na przykład w obsługiwanych przeglądarkach możesz zaimportować moduł KV Storage za pomocą tego kodu (poniżej znajdziesz informacje o używaniu modułu polyfill KV Storage w nieobsługiwanych przeglądarkach):

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

Moduł przechowywania kluczy

Moduł KV Storage jest prosty w użyciu, podobnie jak interfejs localStorage API, ale jego kształt jest bardziej zbliżony do interfejsu JavaScript Map. Zamiast getItem(), setItem() i removeItem(), używa get(), set() i delete(). Zawiera też inne metody podobne do map, które nie są dostępne dla localStorage, takie jak keys(), values() i entries(). Podobnie jak w przypadku Map, klucze nie muszą być ciągami znaków. Mogą to być dowolne typy danych, które można serializować w uporządkowany sposób.

W przeciwieństwie do Map wszystkie metody interfejsu KV Storage zwracają obietnice lub asynchroniczne iteratory (ponieważ główną cechą tego modułu jest to, że nie jest on synchroniczny, w przeciwieństwie do localStorage). Aby zapoznać się ze szczegółami interfejsu API, zapoznaj się z specyfikacją.

Jak widać w przykładowym kodzie powyżej, moduł KV Storage ma jeden domyślny eksport storage i jeden nazwany eksport StorageArea.

storage jest wystąpieniem klasy StorageArea o nazwie 'default', której deweloperzy będą najczęściej używać w kodzie aplikacji. Klasa StorageArea jest przeznaczona do przypadków, w których potrzebna jest dodatkowa izolacja (np. biblioteka zewnętrzna, która przechowuje dane i chce uniknąć konfliktów z danymi przechowywanymi za pomocą domyślnej instancji storage). Dane StorageArea są przechowywane w bazie danych IndexedDB o nazwie kv-storage:${name}, gdzie kv-storage:${name} to nazwa instancji StorageArea.

Oto przykład użycia modułu KV Storage w kodzie:

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

Co zrobić, jeśli przeglądarka nie obsługuje wbudowanego modułu?

Jeśli znasz stosowanie natywnych modułów JavaScript w przeglądarkach, wiesz pewnie, że (przynajmniej do tej pory) importowanie czegokolwiek innego niż adres URL powoduje błąd. Adres std:kv-storage nie jest prawidłowym adresem URL.

W związku z tym pojawia się pytanie: czy musimy czekać, aż wszystkie przeglądarki będą obsługiwać wbudowane moduły, zanim zaczniemy ich używać w naszym kodzie? Na szczęście odpowiedź brzmi: nie.

Wbudowane moduły możesz używać, gdy tylko jeden z przeglądarek je obsługuje, dzięki innej funkcji, z którą eksperymentujemy, czyli map importowanych.

Importowanie map

Mapy importu to mechanizm, dzięki któremu deweloperzy mogą nadawać aliasy identyfikatorom importu w przypadku co najmniej 1 alternatywnego identyfikatora.

Jest to bardzo przydatne, ponieważ daje Ci możliwość zmiany (w czasie działania) sposobu, w jaki przeglądarka rozwiązuje konkretny identyfikator importu w całej aplikacji.

W przypadku wbudowanych modułów możesz w kodzie aplikacji odwoływać się do polyfilla modułu, ale przeglądarka obsługująca wbudowany moduł może zamiast tego wczytać tę wersję.

Oto jak zadeklarować mapę importu, aby działała z modułem KV Storage:

<!-- 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>

Ważnym elementem w powyższym kodzie jest to, że adres URL /path/to/kv-storage-polyfill.mjs jest mapowany na 2 różne zasoby: std:kv-storage, a potem ponownie na oryginalny adres URL /path/to/kv-storage-polyfill.mjs.

Gdy przeglądarka napotka instrukcję importu odwołującą się do tego adresu URL (/path/to/kv-storage-polyfill.mjs), najpierw próbuje załadować plik std:kv-storage, a jeśli się nie uda, wczyta plik /path/to/kv-storage-polyfill.mjs.

Ponownie magia polega na tym, że przeglądarka nie musi obsługiwać map importu ani wbudowanych modułów, aby ta technika działała, ponieważ adres URL przekazywany do instrukcji importu to adres URL polyfill. Rozszerzenie polyfill nie jest rozwiązaniem zapasowym, tylko domyślnym. Wbudowany moduł to stopniowe ulepszanie.

A co z przeglądarkami, które wcale nie obsługują modułów?

Aby używać map importu do warunkowego wczytywania wbudowanych modułów, musisz używać instrukcji import, co oznacza, że musisz też używać skryptów modułu, czyli <script type="module">.

Obecnie ponad 80% przeglądarek obsługuje moduły, a w przypadku przeglądarek, które ich nie obsługują, możesz użyć techniki moduł/brak modułu, aby wyświetlić pakiet starszy. Pamiętaj, że podczas generowania wersji nomodule musisz uwzględnić wszystkie polyfille, ponieważ wiesz na pewno, że przeglądarki, które nie obsługują modułów, na pewno nie będą obsługiwać wbudowanych modułów.

Demonstracja pamięci KV

Aby pokazać, że można używać wbudowanych modułów, zachowując przy tym obsługę starszych przeglądarek, przygotowałem prezentację, która wykorzystuje wszystkie opisane powyżej techniki i działa we wszystkich przeglądarkach:

  • Przeglądarki, które obsługują moduły, importowanie map i wbudowany moduł, nie wczytują niepotrzebnego kodu.
  • Przeglądarki, które obsługują moduły i importowanie map, ale nie obsługują wbudowanego modułu, wczytują polyfill usługi KV Storage (za pomocą modułu wczytywania przeglądarki).
  • Przeglądarki, które obsługują moduły, ale nie obsługują map importowanych, wczytują również polyfill do przechowywania w pamieci KV (za pomocą modułu wczytującego przeglądarki).
  • Przeglądarki, które nie obsługują modułów, otrzymują polyfill do usługi KV Storage w ramach starszego pakietu (wczytanego za pomocą <script nomodule>).

Wersja demonstracyjna jest hostowana na Glitch, więc możesz wyświetlić jej kod źródłowy. Szczegółowe wyjaśnienie implementacji znajdziesz też w README. Jeśli chcesz zobaczyć, jak to działa, możesz to zrobić.

Aby zobaczyć działanie natywnego wbudowanego modułu, musisz załadować wersję demonstracyjną w Chrome 74 lub nowszej z włączoną flagą funkcji eksperymentalnych platformy internetowej (chrome://flags/#enable-experimental-web-platform-features).

Możesz sprawdzić, czy wczytany jest wbudowany moduł, ponieważ w panelu źródeł w DevTools nie zobaczysz skryptu polyfill. Zamiast tego zobaczysz wersję wbudowanego modułu (ciekawostka: możesz sprawdzić kod źródłowy modułu lub umieścić w nim punkty przerwania):

Źródło modułu KV Storage w Narzędziach deweloperskich w Chrome

Prześlij nam opinię

Mamy nadzieję, że to wprowadzenie pozwoliło Ci poznać możliwości wbudowanych modułów. Mam nadzieję, że nie możesz się już doczekać. Zachęcamy deweloperów do wypróbowania modułu KV Storage (oraz wszystkich nowych funkcji opisanych tutaj) i przesłania nam opinii.

Oto linki do GitHuba, gdzie możesz przesłać opinię na temat każdej z funkcji wymienionych w tym artykule:

Jeśli Twoja witryna korzysta obecnie z localStorage, spróbuj przejść na interfejs KV Storage API, aby sprawdzić, czy spełnia on wszystkie Twoje potrzeby. Jeśli zarejestrujesz się w ramach testów wersji próbnej usługi KV Storage origin, możesz już dziś wdrożyć te funkcje. Wszyscy użytkownicy powinni odczuć korzyści wynikające z lepszej wydajności pamięci masowej, a użytkownicy Chrome w wersji 74 lub nowszej nie będą musieli płacić za pobieranie.