Istnieje wiele różnych opcji przechowywania danych w przeglądarce. Który z nich najlepiej odpowiada Twoim potrzebom?
Połączenia z internetem mogą być niestabilne lub niedostępne, dlatego obsługa offline i niezawodne działanie to typowe cechy progresywnych aplikacji internetowych. Nawet w idealnych warunkach sieci bezprzewodowej rozsądne korzystanie z pamięci podręcznej i innych technik przechowywania danych może znacznie poprawić wrażenia użytkowników. Istnieje kilka sposobów buforowania statycznych zasobów aplikacji (HTML, JavaScript, CSS, obrazy itp.) i danych (dane użytkownika, artykuły z wiadomościami itp.). Które rozwiązanie jest najlepsze? Ile danych możesz przechowywać? Jak zapobiec jego usunięciu?
Co wybrać?
Oto ogólne zalecenia dotyczące przechowywania zasobów:
- W przypadku zasobów sieciowych niezbędnych do wczytania aplikacji użyj interfejsu Cache Storage API (część skryptów service worker).
- W przypadku treści opartych na plikach używaj prywatnego systemu plików źródła (OPFS).
- W przypadku innych danych użyj IndexedDB (z opakowaniem obietnic).
IndexedDB, OPFS i interfejs Cache Storage API są obsługiwane we wszystkich nowoczesnych przeglądarkach.
Są asynchroniczne i nie blokują wątku głównego (ale istnieje też synchroniczny wariant OPFS, który jest dostępny wyłącznie w instancjach roboczych sieci Web). Są one dostępne z obiektu window, skryptów web worker i skryptów service worker, dzięki czemu można ich używać w dowolnym miejscu w kodzie.
Co z innymi mechanizmami przechowywania danych?
W przeglądarce dostępnych jest kilka innych mechanizmów pamięci, ale mają one ograniczone zastosowanie i mogą powodować znaczne problemy z wydajnością.
SessionStorage jest powiązany z konkretną kartą i istnieje tylko przez czas jej otwarcia. Może być przydatny do przechowywania niewielkich ilości informacji związanych z sesją, np. klucza IndexedDB. Należy używać jej ostrożnie, ponieważ jest synchroniczna i blokuje wątek główny. Jest ograniczony do około 5 MB i może zawierać tylko ciągi znaków. Ponieważ jest on powiązany z kartą, nie jest dostępny dla skryptów web worker ani service worker.
Należy unikać LocalStorage, ponieważ jest to metoda synchroniczna i będzie blokować wątek główny. Jest ograniczony do około 5 MB i może zawierać tylko ciągi znaków. LocalStorage nie jest dostępny z poziomu skryptów web worker ani skryptów service worker.
Pliki cookie mają swoje zastosowania, ale nie powinny być używane do przechowywania danych. Pliki cookie są wysyłane z każdym żądaniem HTTP, więc przechowywanie czegoś więcej niż niewielkiej ilości danych znacznie zwiększy rozmiar każdego żądania sieciowego. Są synchroniczne i nie można uzyskać do nich dostępu z poziomu skryptów web worker. Podobnie jak LocalStorage i SessionStorage, pliki cookie są ograniczone tylko do ciągów znaków.
Interfejs File System Access API został zaprojektowany tak, aby umożliwiać użytkownikom odczytywanie i edytowanie plików w lokalnym systemie plików. Użytkownik musi przyznać uprawnienia, zanim strona będzie mogła odczytać lub zapisać dowolny plik lokalny, a uprawnienia nie są zachowywane między sesjami, chyba że uchwyt pliku jest przechowywany w pamięci podręcznej w IndexedDB. Interfejs File System Access API najlepiej sprawdza się w przypadkach takich jak edytory, w których musisz otworzyć plik, zmodyfikować go, a następnie zapisać zmiany w pliku.
Interfejsy File System API i FileWriter API udostępniają metody odczytu i zapisu plików w systemie plików w piaskownicy. Chociaż jest asynchroniczny, nie jest zalecany, ponieważ jest dostępny tylko w przeglądarkach opartych na Chromium.
Ile danych mogę przechowywać?
Krótko mówiąc, dużo – co najmniej kilkaset megabajtów, a potencjalnie setki gigabajtów lub więcej. Implementacje przeglądarek różnią się, ale ilość dostępnego miejsca na dane zwykle zależy od ilości dostępnego miejsca na urządzeniu.
- Chrome pozwala przeglądarce na wykorzystanie do 80% całkowitego miejsca na dysku. Źródło może wykorzystywać do 60% łącznego miejsca na dysku. Aby określić maksymalny dostępny limit, możesz użyć interfejsu StorageManager API. Inne przeglądarki oparte na Chromium mogą się różnić.
- W trybie incognito Chrome zmniejsza ilość miejsca na dane, z którego może korzystać źródło, do około 5% całkowitego miejsca na dysku.
- Jeśli użytkownik włączył w Chrome opcję „Wyczyść pliki cookie i dane witryn w momencie zamknięcia wszystkich okien”, limit miejsca na dane jest znacznie zmniejszony do maksymalnie około 300 MB.
- Firefox pozwala przeglądarce na wykorzystanie do 50% wolnego miejsca na dysku. Grupa eTLD+1 (np.
example.com,www.example.comifoo.bar.example.com) może używać maksymalnie 2 GB. Możesz użyć interfejsu StorageManager API, aby określić, ile miejsca jest jeszcze dostępne. - Safari (zarówno na komputerach, jak i urządzeniach mobilnych) zezwala na około 1 GB. Po osiągnięciu limitu Safari wyświetli użytkownikowi prośbę o zwiększenie limitu o 200 MB. Nie udało mi się znaleźć żadnej oficjalnej dokumentacji na ten temat.
- Jeśli PWA zostanie dodana do ekranu głównego w mobilnej wersji Safari, tworzy nowy kontener pamięci i nic nie jest udostępniane między PWA a mobilną wersją Safari. Po osiągnięciu limitu miejsca dla zainstalowanej aplikacji PWA nie ma możliwości poproszenia o dodatkowe miejsce.
W przeszłości, jeśli witryna przekroczyła określony próg przechowywanych danych, przeglądarka prosiła użytkownika o przyznanie uprawnień do korzystania z większej ilości danych. Jeśli na przykład źródło wykorzystało ponad 50 MB, przeglądarka poprosi użytkownika o zgodę na przechowywanie do 100 MB, a następnie będzie pytać ponownie co 50 MB.
Obecnie większość nowoczesnych przeglądarek nie wyświetla użytkownikowi prośby o zgodę i pozwala witrynie na wykorzystanie przydzielonego limitu. Wyjątkiem jest Safari, która po przekroczeniu limitu miejsca na dane wyświetla prośbę o zgodę na zwiększenie przydzielonego limitu przydziału. Jeśli źródło spróbuje wykorzystać więcej niż przydzielony limit, kolejne próby zapisu danych zakończą się niepowodzeniem.
Jak sprawdzić, ile miejsca jest dostępne?
W wielu przeglądarkach możesz użyć interfejsu StorageManager API, aby określić ilość miejsca dostępnego dla źródła i ilość miejsca, które jest wykorzystywane. Podaje łączną liczbę bajtów używanych przez IndexedDB i interfejs Cache API oraz umożliwia obliczenie przybliżonej ilości pozostałego dostępnego miejsca na dane.
if (navigator.storage && navigator.storage.estimate) {
const quota = await navigator.storage.estimate();
// quota.usage -> Number of bytes used.
// quota.quota -> Maximum number of bytes available.
const percentageUsed = (quota.usage / quota.quota) * 100;
console.log(`You've used ${percentageUsed}% of the available storage.`);
const remaining = quota.quota - quota.usage;
console.log(`You can write up to ${remaining} more bytes.`);
}
Musisz przechwytywać błędy związane z przekroczeniem limitu (patrz poniżej). W niektórych przypadkach dostępny limit może przekraczać rzeczywistą ilość dostępnego miejsca na dane.
Zbadaj
Podczas tworzenia aplikacji możesz używać narzędzi deweloperskich w przeglądarce, aby sprawdzać różne typy pamięci i usuwać wszystkie zapisane dane.
W Chrome 88 dodaliśmy nową funkcję, która umożliwia zastąpienie limitu miejsca na dane witryny w panelu Pamięć. Ta funkcja umożliwia symulowanie różnych urządzeń i testowanie działania aplikacji w scenariuszach, w których dostępna jest niewielka ilość miejsca na dysku. Kliknij Aplikacja, a następnie Pamięć, zaznacz pole wyboru Symuluj niestandardowy limit miejsca na dane i wpisz dowolną prawidłową liczbę, aby zasymulować limit miejsca na dane.
How to handle going over quota?
Co zrobić, gdy przekroczysz limit? Najważniejsze jest, aby zawsze przechwytywać i obsługiwać błędy zapisu, niezależnie od tego, czy jest to QuotaExceededError, czy coś innego. Następnie, w zależności od projektu aplikacji, zdecyduj, jak postępować.
Możesz na przykład usunąć treści, które nie były używane od dłuższego czasu, usunąć dane na podstawie rozmiaru lub umożliwić użytkownikom wybór tego, co chcą usunąć.
Zarówno IndexedDB, jak i interfejs Cache API zgłaszają błąd DOMError o nazwie QuotaExceededError, gdy przekroczysz dostępny limit.
IndexedDB
Jeśli źródło przekroczyło limit, próby zapisu w IndexedDB zakończą się niepowodzeniem. Zostanie wywołany moduł obsługi onabort() transakcji, który przekaże zdarzenie.
Zdarzenie będzie zawierać element DOMException we właściwości błędu. Sprawdzenie błędu name zwróci wartość QuotaExceededError.
const transaction = idb.transaction(['entries'], 'readwrite');
transaction.onabort = function(event) {
const error = event.target.error; // DOMException
if (error.name == 'QuotaExceededError') {
// Fallback code goes here
}
};
Cache API
Jeśli źródło przekroczyło limit, próby zapisu w interfejsie Cache API zostaną odrzucone z błędem QuotaExceededError DOMException.
try {
const cache = await caches.open('my-cache');
await cache.add(new Request('/sample1.jpg'));
} catch (err) {
if (error.name === 'QuotaExceededError') {
// Fallback code goes here
}
}
Jak działa eksmisja?
Pamięć internetowa jest podzielona na 2 kategorie: „Best Effort” (Najlepsze wyniki) i „Persistent” (Trwała). W miarę możliwości oznacza, że pamięć może zostać wyczyszczona przez przeglądarkę bez przerywania pracy użytkownika, ale jest mniej trwała w przypadku danych długoterminowych lub krytycznych. Pamięć trwała nie jest automatycznie czyszczona, gdy brakuje miejsca na dane. Użytkownik musi ręcznie wyczyścić tę pamięć (w ustawieniach przeglądarki).
Domyślnie dane witryny (w tym IndexedDB, interfejs Cache API itp.) należą do kategorii „najlepsze możliwe działanie”, co oznacza, że jeśli witryna nie zażądała pamięci trwałej, przeglądarka może według własnego uznania usunąć dane witryny, np. gdy na urządzeniu jest mało pamięci urządzenia.
Zasada wykluczania w przypadku możliwie najlepszej obsługi:
- Przeglądarki oparte na Chromium zaczną usuwać dane, gdy zabraknie im miejsca. Najpierw zostaną usunięte wszystkie dane witryny z najrzadziej używanego źródła, a potem z następnego, aż przeglądarka nie będzie już przekraczać limitu.
- Firefox zacznie usuwać dane, gdy dostępne miejsce na dysku zostanie zapełnione. Najpierw usunie wszystkie dane witryny z najrzadziej używanego źródła, a potem z następnego, aż przeglądarka nie będzie już przekraczać limitu.
- Wcześniej Safari nie usuwała danych, ale niedawno wprowadzono w niej nowy, 7-dniowy limit na wszystkie pamięci masowe z możliwością zapisu (patrz poniżej).
Od wersji iOS i iPadOS 13.4 oraz Safari 13.1 na macOS obowiązuje 7-dniowy limit na wszystkie pamięci masowe, do których można zapisywać skrypty, w tym IndexedDB, rejestrację skryptu service worker i interfejs Cache API. Oznacza to, że Safari usunie całą zawartość z pamięci podręcznej po 7 dniach korzystania z przeglądarki, jeśli użytkownik nie wejdzie w interakcję z witryną. Ta zasada usuwania nie dotyczy zainstalowanych aplikacji PWA, które zostały dodane do ekranu głównego. Szczegółowe informacje znajdziesz w artykule Full Third-Party Cookie Blocking and More (Pełne blokowanie plików cookie innych firm i inne funkcje) na blogu WebKit.
Zasobniki na dane
Główną ideą interfejsu Storage Buckets API jest umożliwienie witrynom tworzenia wielu zasobników na dane, przy czym przeglądarka może usunąć każdy zasobnik niezależnie od innych. Dzięki temu deweloperzy mogą określić priorytety usuwania, aby mieć pewność, że najważniejsze dane nie zostaną usunięte.
Bonus: dlaczego warto używać wrappera dla IndexedDB
IndexedDB to interfejs API niskiego poziomu, który wymaga znacznej konfiguracji przed użyciem, co może być szczególnie uciążliwe w przypadku przechowywania danych o niskiej złożoności. W przeciwieństwie do większości nowoczesnych interfejsów API opartych na obietnicach jest on oparty na zdarzeniach. Opakowania obietnic, takie jak idb dla IndexedDB, ukrywają niektóre zaawansowane funkcje, ale co ważniejsze, ukrywają złożone mechanizmy (np. transakcje, obsługę wersji schematu) dostarczane z biblioteką IndexedDB.
Dodatek: SQLite Wasm
Po wycofaniu i usunięciu Web SQL z Chrome Google we współpracy z osobami zarządzającymi popularną bazą danych SQLite zaoferowało zamiennik Web SQL oparty na SQLite. Szczegółowe informacje o tym, jak używać SQLite Wasm, znajdziesz w artykule SQLite Wasm in the browser backed by the Origin Private File System (SQLite Wasm w przeglądarce z wykorzystaniem prywatnego systemu plików źródła).
Podsumowanie
Dawno minęły czasy ograniczonego miejsca na dane i proszenia użytkownika o przechowywanie coraz większej ilości danych. Witryny mogą skutecznie przechowywać wszystkie zasoby i dane potrzebne do działania. Za pomocą interfejsu StorageManager API możesz sprawdzić, ile miejsca jest dostępne i ile zostało wykorzystane. Dzięki pamięci trwałej możesz chronić dane przed usunięciem, chyba że użytkownik sam je usunie.
Dodatkowe materiały
Dziękujemy
Specjalne podziękowania dla Jarryda Goodmana, Phila Waltona, Eijiego Kitamury, Daniela Murphy'ego, Darwina Huanga, Josha Bella, Marijna Kruisselbrinka i Victora Costana za sprawdzenie tego przewodnika. Dziękujemy Eijiemu Kitamurze, Addy'emu Osmani i Marcowi Cohenowi, którzy napisali oryginalne artykuły, na których opiera się ten tekst. Eiji napisał przydatne narzędzie o nazwie Browser Storage Abuser, które pomogło nam sprawdzić obecne działanie. Dzięki temu możesz przechowywać jak najwięcej danych i sprawdzać limity miejsca na dane w przeglądarce. Dziękujemy François Beaufortowi, który przeanalizował Safari, aby określić limity miejsca na dane, oraz Thomasowi Steinerowi za dodanie informacji o prywatnym systemie plików punktu początkowego, zasobnikach na dane i SQLite Wasm oraz za ogólną aktualizację treści w 2024 r.