Miejsce na dane w internecie

Istnieje wiele różnych opcji przechowywania danych w przeglądarce. Które rozwiązanie najlepiej odpowiada Twoim potrzebom?

Połączenia z internetem mogą być niestabilne lub nieobecne w przypadku korzystania z aplikacji w ruchu, dlatego progresywne aplikacje internetowe często oferują obsługę offline i niezawodną wydajność. Nawet w idealnych bezprzewodowych środowiskach rozsądne korzystanie z buforowania i innych technik przechowywania może znacznie poprawić wrażenia użytkownika. Zasoby statyczne aplikacji (HTML, JavaScript, CSS, obrazy itp.) oraz dane (dane o użytkownikach, artykuły itp.) można zapisać w pamięci podręcznej na kilka sposobów. Ale które rozwiązanie jest najlepsze? Ile możesz przechowywać? Jak zapobiegać wyrzucaniu?

Oto ogólna rekomendacja dotycząca przechowywania zasobów:

IndexedDB, OPFS i Cache Storage API są obsługiwane w każdej nowoczesnej przeglądarce. Są one asynchroniczne i nie blokują wątku głównego (chociaż istnieje też wariant synchroniczny OPFS, który jest dostępny wyłącznie w instancji roboczej sieci). Są one dostępne z obiektu window, web workerów i service workerów, co umożliwia ich używanie w dowolnym miejscu w kodzie.

A co z innymi mechanizmami przechowywania?

W przeglądarce dostępnych jest kilka innych mechanizmów przechowywania, ale mają one ograniczone zastosowanie i mogą powodować poważne problemy z wydajnością.

SessionStorage jest specyficzny dla karty i ograniczony do jej czasu trwania. Może być przydatny do przechowywania niewielkich ilości informacji dotyczących sesji, np. klucza IndexedDB. Należy go używać ostrożnie, ponieważ jest synchroniczny i blokuje wątek główny. Jego rozmiar jest ograniczony do około 5 MB i może zawierać tylko ciągi znaków. Jest ona powiązana z konkretną kartą, więc nie jest dostępna dla procesów web workerów ani service workerów.

Należy unikać korzystania z LocalStorage, ponieważ jest to obiekt synchroniczny, który blokuje wątek główny. Jego rozmiar jest ograniczony do około 5 MB i może zawierać tylko ciągi znaków. LocalStorage nie jest dostępny z poziomu wątków web worker ani wątków service worker.

Pliki cookie mają swoje zastosowanie, ale nie powinny być używane do przechowywania danych. Pliki cookie są wysyłane z każdym żądaniem HTTP, więc przechowywanie większej ilości danych znacznie zwiększy rozmiar każdego żądania internetowego. Są one synchroniczne i niedostępne dla web workerów. Podobnie jak w przypadku LocalStorage i SessionStorage, pliki cookie są ograniczone tylko do ciągów znaków.

Interfejs File System Access API został zaprojektowany tak, aby umożliwić użytkownikom odczytywanie i edytowanie plików w ich lokalnym systemie plików. Użytkownik musi przyznać uprawnienia, zanim strona będzie mogła odczytać lub zapisać dowolny plik lokalny. Uprawnienia nie są zachowywane w trakcie sesji, chyba że uchwyt pliku jest przechowywany w buforze w IndexedDB. Interfejs File System Access API najlepiej sprawdza się w przypadku edytorów, w których trzeba otworzyć plik, zmodyfikować go, a potem ewentualnie zapisać zmiany w pliku.

Interfejsy File System API i FileWriter API udostępniają metody odczytu i zapisu plików do systemu plików w piaskownicy. Jest on asynchroniczny, ale 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 czasem nawet setki gigabajtów. Implementacje przeglądarek różnią się od siebie, ale ilość dostępnego miejsca na dane zależy zwykle od ilości miejsca dostępnej na urządzeniu.

  • Chrome pozwala przeglądarce używać do 80% całkowitego miejsca na dysku. Źródło może zajmować do 60% łącznej ilości miejsca na dysku. Aby określić maksymalną dostępną pulę, możesz użyć interfejsu API StorageManager. Inne przeglądarki oparte na Chromium mogą działać inaczej.
    • W trybie incognito Chrome ogranicza ilość miejsca na dane, z którego może korzystać domen, do około 5% łącznej ilości 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 zostanie znacznie zmniejszony do około 300 MB.
  • Firefox pozwala przeglądarce używać do 50% wolnego miejsca na dysku. Grupa eTLD+1 (np. example.com, www.example.comfoo.bar.example.com) może zużyć do 2 GB. Aby sprawdzić, ile miejsca jest jeszcze dostępne, możesz użyć interfejsu StorageManager API.
  • Safari (na komputerach i urządzeniach mobilnych) pozwala na około 1 GB. Po osiągnięciu limitu Safari wyświetli użytkownikowi komunikat z 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 Safari na urządzeniu mobilnym, utworzy nowy kontener pamięci, a PWA i Safari na urządzeniu mobilnym nie będą ze sobą niczego współdzielić. Po osiągnięciu limitu dla zainstalowanej aplikacji PWA nie ma możliwości przesłania prośby o dodatkowe miejsce na dane.

W przeszłości, gdy witryna przekraczała określony limit 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 zużywa ponad 50 MB, przeglądarka prosi użytkownika o zezwolenie na przechowywanie do 100 MB, a potem ponownie co 50 MB.

Obecnie większość nowoczesnych przeglądarek nie wyświetla użytkownikowi żadnego komunikatu i pozwala witrynie wykorzystać przydzielony jej przydział. Wyjątkiem jest przeglądarka Safari, która wyświetla prośbę o pozwolenie na zwiększenie przydzielonego limitu miejsca po przekroczeniu limitu miejsca. Jeśli pochodzenie spróbuje użyć więcej niż przydzielony mu limit, kolejne próby zapisu danych zakończą się niepowodzeniem.

Jak mogę 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 ile miejsca jest używane. Raport zawiera łączną liczbę bajtów używanych przez IndexedDB i Cache API oraz umożliwia obliczenie przybliżonej ilości 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 wykrywać błędy związane z przekroczeniem limitu (patrz poniżej). W niektórych przypadkach dostępna pula może przekraczać rzeczywistą ilość dostępnego miejsca.

Zbadaj

Podczas tworzenia aplikacji możesz użyć narzędzi programistycznych w przeglądarce, aby sprawdzić różne typy pamięci i wyczyścić wszystkie zapisane dane.

W Chrome 88 dodano nową funkcję, która umożliwia zastąpienie limitu miejsca na dane witryny w panelu Miejsce na dane. Ta funkcja umożliwia symulowanie różnych urządzeń i testowanie działania aplikacji w scenariuszach niskiej dostępnej przestrzeni na dysku. Kliknij kolejno Aplikacja i Pamięć, zaznacz pole wyboru Symuluj niestandardowy limit miejsca na dane i wpisz dowolną liczbę, aby symulować limit miejsca na dane.

Podczas pracy nad tym przewodnikiem napisałem proste narzędzie, które ma na celu szybkie wykorzystanie jak największej ilości miejsca na dane. To szybki sposób na eksperymentowanie z różnymi mechanizmami przechowywania i sprawdzanie, co się dzieje, gdy wykorzystasz cały limit.

Jak postępować, gdy przekroczysz limit?

Co należy zrobić, gdy przekroczysz limit miejsca? Najważniejsze jest to, aby zawsze wykrywać 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 sobie z tym poradzić. Możesz na przykład usunąć treści, do których nie był uzyskiwany dostęp od dłuższego czasu, usunąć dane na podstawie ich rozmiaru lub umożliwić użytkownikom wybranie treści, które chcą usunąć.

Zarówno IndexedDB, jak i Cache API zgłaszają błąd DOMError o nazwie QuotaExceededError, gdy przekroczysz dostępną pulę.

IndexedDB

Jeśli limit został przekroczony, próby zapisu do IndexedDB zakończą się niepowodzeniem. Zostanie wywołany moduł obsługi zdarzenia onabort() transakcji, do którego zostanie przekazane zdarzenie. Zdarzenie będzie zawierać DOMException we właściwości błędu. Sprawdzanie błędu name zwraca 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 pochodzenie przekroczyło swój limit, próby zapisu do interfejsu Cache API zostaną odrzucone z powodem 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 wyrzucanie?

Pamięć internetowa jest podzielona na 2 kategorie: „Best Effort” i „Persistent”. W miarę możliwości oznacza, że przeglądarka może wyczyścić pamięć bez przerywania pracy użytkownika, ale nie jest to trwałe rozwiązanie w przypadku danych długoterminowych lub krytycznych. Pamięć trwała nie jest automatycznie usuwana, gdy brakuje miejsca. Użytkownik musi ręcznie wyczyścić to miejsce (za pomocą ustawień przeglądarki).

Domyślnie dane witryny (w tym IndexedDB, interfejs Cache API itp.) należą do kategorii „najlepszego wysiłku”, co oznacza, że jeśli witryna nie poprosi o trwałe przechowywanie, przeglądarka może usunąć dane witryny według własnego uznania, na przykład gdy na urządzeniu jest mało miejsca.

Zasady usuwania z usług o najlepszych możliwościach:

  • Gdy przeglądarki oparte na Chromium wyczerpią miejsce, zaczną usuwać dane, najpierw usuwając wszystkie dane witryn z najrzadziej niedawno używanych źródeł, a potem z kolejnych, aż do momentu, gdy nie przekroczą limitu.
  • Gdy dostępne miejsce na dysku się zapełni, Firefox zacznie usuwać dane, najpierw usuwając wszystkie dane witryn z najrzadziej niedawno używanych źródeł, a potem kolejne, aż do momentu, gdy przeglądarka nie przekroczy limitu.
  • Wcześniej Safari nie usuwało danych, ale niedawno wprowadziliśmy nowe ograniczenie 7-dniowe dla całej pamięci masowej z możliwością zapisu (patrz poniżej).

Od wersji iOS i iPadOS 13.4 oraz Safari 13.1 na komputerach Mac wprowadzono 7-dniowy limit dla wszystkich miejsc do przechowywania danych, do których można zapisywać skrypty, w tym IndexedDB, rejestrację usług i interfejs Cache API. Oznacza to, że po 7 dniach korzystania z Safari, jeśli użytkownik nie będzie wchodzić w interakcję z witryną, Safari usunie z pamięci podręcznej wszystkie treści. Ta zasada usuwania nie dotyczy zainstalowanych PWA, które zostały dodane do ekranu głównego. Więcej informacji znajdziesz w artykule Pełne blokowanie plików cookie innych firm i inne funkcje na blogu WebKit.

Zasobniki pamięci masowej

Podstawowym założeniem interfejsu Storage Buckets API jest umożliwienie witrynom tworzenia wielu zasobników na dane, z których każdy może być usuwany niezależnie od innych. Dzięki temu deweloperzy mogą określić priorytety usuwania, aby mieć pewność, że nie zostaną usunięte najcenniejsze dane.

Bonus: dlaczego warto używać owijarki dla IndexedDB

IndexedDB to interfejs API niskiego poziomu, który wymaga znacznej konfiguracji przed użyciem. Może to być szczególnie uciążliwe w przypadku przechowywania prostych danych. W przeciwieństwie do większości współczesnych interfejsów API opartych na obietnicach działa on na podstawie zdarzeń. Opakowania obietnic, takie jak idb w przypadku IndexedDB, ukrywają niektóre zaawansowane funkcje, ale co ważniejsze, ukrywają też złożone mechanizmy (np. transakcje, wersjonowanie schematu), które są dostępne w bibliotece IndexedDB.

Bonus: SQLite Wasm

Po wycofaniu i usunięciu z Chrome interfejsu Web SQL firma Google współpracowała z utrzymawcami popularnej bazy danych SQLite, aby zaoferować zamiennik Web SQL oparty na SQLite. Więcej informacji o tym, jak korzystać z tej funkcji, znajdziesz w artykule SQLite Wasm w przeglądarce obsługiwanym przez prywatny system plików Origin.

Podsumowanie

To już przeszłość, że użytkownicy mieli ograniczoną ilość miejsca na dane i stale musieli prosić o przechowywanie coraz większej ilości danych. Strony mogą przechowywać wszystkie zasoby i dane potrzebne do działania. Za pomocą interfejsu StorageManager API możesz sprawdzić, ile miejsca masz do dyspozycji i ile go wykorzystałeś. A dzięki trwałemu magazynowi danych możesz chronić dane przed usunięciem, chyba że użytkownik je usunie.

Dodatkowe materiały

Dziękujemy

Szczególne podziękowania kierujemy do Jarryda Goodmana, Phila Waltona, Eiji Kitamury, Daniela Murphy'ego, Darwina Huanga, Josha Bella, Marijna Kruisselbrinka i Victora Costana za sprawdzenie tego przewodnika. Dziękujemy Eiji Kitamurze, Addie Osmani i Marcowi Cohenowi za napisanie oryginalnych artykułów, na których się opieramy. Eiji napisał przydatne narzędzie o nazwie Browser Storage Abuser, które było przydatne do weryfikacji bieżącego zachowania. Pozwala on przechowywać jak najwięcej danych i sprawdza limity miejsca w pamięci przeglądarki. Dziękujemy Françoisowi Beaufortowi, który przeanalizował Safari, aby ustalić limity pamięci, oraz Thomasowi Steinerowi za dodanie informacji o prywatnym systemie plików źródłowych, zasobnikach pamięci, SQLite Wasm i ogólnej aktualizacji treści w 2024 r.

Obraz główny pochodzi od Guillaume Bolduca z Unsplash.