Miejsce na dane w internecie

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

Połączenia z internetem mogą być niestabilne lub w ogóle nie działać, 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żna przechowywać? Jak zapobiegasz jego usunięciu?

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 poziomu obiektu window, mechanizmów Service Worker i mechanizmów Service Worker, dzięki czemu można ich używać w dowolnym miejscu w kodzie.

Co z innymi mechanizmami przechowywania danych?

Przeglądarka oferuje kilka innych mechanizmów przechowywania danych, ale są one używane w ograniczonym zakresie i mogą powodować poważne problemy z wydajnością.

SessionStorage jest specyficzny dla karty i ograniczony do jej czasu trwania. Może być przydatna do przechowywania niewielkich ilości informacji związanych z sesją, 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. Ze względu na to, że dotyczy on tylko kart, nie jest dostępny dla procesów internetowych ani service worker.

Unikaj 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 zastosowania, 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, aby umożliwić 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. 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 takich przypadkach jak edytory, w których trzeba otworzyć plik, zmodyfikować go, a następnie zapisać z powrotem zmiany w pliku.

Interfejsy File System API i FileWriter API udostępniają metody odczytu i zapisu plików do systemu plików w piaskownicy. Choć jest asynchroniczna, nie zalecamy jej, ponieważ jest dostępna 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 nawet setki gigabajtów. Implementacje przeglądarek są różne, ale ilość dostępnego miejsca zwykle zależy od ilości miejsca dostępnego na urządzeniu.

  • Chrome umożliwia przeglądarce wykorzystanie do 80% całego miejsca na dysku. Źródło może zajmować do 60% łącznej ilości miejsca na dysku. Maksymalny dostępny limit możesz określić za pomocą interfejsu StorageManager API. Inne przeglądarki oparte na Chromium mogą działać inaczej.
    • W trybie incognito Chrome zmniejsza ilość miejsca na dane wykorzystywanego przez źródło do około 5% całkowitego miejsca na dysku.
    • Jeśli użytkownik ma włączoną w Chrome opcję „Wyczyść pliki cookie i dane witryn w momencie zamknięcia wszystkich okien”, limit miejsca na dane jest 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. Możesz użyć interfejsu StorageManager API, aby sprawdzić, ile miejsca jest jeszcze dostępne.
  • Safari (na komputerach i urządzeniach mobilnych) pozwala na około 1 GB. Gdy limit zostanie osiągnięty, Safari wyświetli użytkownikowi komunikat z prośbą o zwiększenie limitu o 200 MB. Nie udało mi się znaleźć żadnych oficjalnych dokumentów 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.

Jeśli w przeszłości witryna przekroczyła określony próg przechowywanych danych, przeglądarka prosiła użytkownika o zezwolenie na korzystanie 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 limit, kolejne próby zapisu danych zakończą się niepowodzeniem.

Jak sprawdzić, ile miejsca jest dostępne?

W wielu przeglądarkach za pomocą interfejsu StorageManager API możesz określić ilość miejsca na dane dostępnego dla źródła oraz ilość wykorzystywanego przez nie miejsca. 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 może się zdarzyć, że dostępny limit przekroczy 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 dodaliśmy nową funkcję, która umożliwia zastąpienie limitu miejsca na dane witryny w panelu pamięci. Ta funkcja umożliwia symulowanie różnych urządzeń i testowanie działania aplikacji w scenariuszach niskiej dostępnej przestrzeni na dysku. Wybierz Aplikacja, a następnie Miejsce na dane, zaznacz pole wyboru Symuluj niestandardowy limit miejsca na dane i wpisz dowolną prawidłową 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 danych i sprawdzanie, co się stanie po zużyciu całego limitu.

Jak poradzić sobie z przekroczeniem limitu?

Co należy zrobić, gdy przekroczysz limit? 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 ją obsługiwać. 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ąć.

Po przekroczeniu limitu zarówno IndexedDB, jak i interfejs Cache API wysyłają żądanie DOMError o nazwie QuotaExceededError.

IndexedDB

Jeśli źródło przekroczyło limit, próby zapisu w 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. Zaznaczenie błędu name spowoduje zwrócenie 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”. Najlepsze wyniki oznacza, że przeglądarka może wyczyścić pamięć bez zakłócania działania użytkownika, ale jest mniej trwałe w przypadku długoterminowych lub krytycznych danych. Pamięć trwała nie jest automatycznie czyszczona, gdy zaczyna brakować miejsca. Użytkownik musi ręcznie wyczyścić to miejsce (za pomocą ustawień przeglądarki).

Domyślnie dane strony (w tym IndexedDB, Cache API itp.) zaliczają się do kategorii „najlepsze działanie”. Oznacza to, że jeśli strona żąda trwałego przechowywania danych, przeglądarka może według własnego uznania usunąć dane witryny, np. gdy na urządzeniu jest mało miejsca.

Zasada usuwania z pamięci w przypadku najlepszych wysiłków:

  • 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 witryny z najrzadziej niedawno używanego źródła, a potem kolejne, aż do momentu, gdy przeglądarka nie przekroczy limitu.
  • Przeglądarka Safari wcześniej nie usuwała danych, ale ostatnio wdrożyła nowy 7-dniowy limit całej pamięci dostępnej do zapisu (patrz poniżej).

Począwszy od systemów iOS i iPadOS 13.4 oraz Safari 13.1 w systemie macOS obowiązuje 7-dniowy limit dotyczący całej pamięci masowej skryptów, w tym IndexedDB, rejestracji mechanizmów Service Worker oraz interfejsu 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. Szczegółowe informacje znajdziesz w sekcji Blokowanie plików cookie innych firm i nie tylko 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 przez przeglądarkę niezależnie od innych zasobników. 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ń. Kody obiecujące, np.idb dla IndexedDB, ukrywają niektóre zaawansowane funkcje, ale co ważniejsze, ukrywają złożone maszyny (np. transakcje, obsługę wersji schematu) dostarczane z biblioteką IndexedDB.

Bonus: SQLite Wasm

Po wycofaniu Web SQL i usunięciu go z Chrome firma Google współpracowała z zespołami ds. obsługi popularnej bazy danych SQLite, aby zaoferować zamiennik Web SQL oparty na SQLite. Szczegółowe informacje o tym, jak z niej korzystać, znajdziesz w artykule SQLite Wasm w przeglądarce obsługiwanej przez Origin Private File System.

Podsumowanie

Minęły czasy ograniczonego miejsca na dane i zachęcania użytkowników do przechowywania coraz większej ilości danych. Witryny mogą skutecznie przechowywać wszystkie zasoby i dane potrzebne do uruchomienia. Za pomocą interfejsu StorageManager API możesz sprawdzić, ile miejsca masz do dyspozycji i ile go wykorzystałeś. Dzięki trwałemu miejscu na dane możesz chronić je przed usunięciem, chyba że użytkownik je usunie.

Dodatkowe materiały

Dziękujemy

Szczególne 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ęki nim Eiji Kitamura, Addy Osmani i Marc Cohen napisały oryginalne artykuły, które bazują na tych treściach. 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 poznać limity pamięci, oraz Thomasowi Steinerowi za dodanie informacji o prywatnym systemie plików źródłowych, zasobnikach pamięci, SQLite Wasm oraz ogólnej aktualizacji treści w 2024 r.

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