Kiedy wygasają elementy w lokalnej pamięci HTML5?

337

Jak długo dostępne są dane przechowywane w localStorage (jako część DOM Storage w HTML5)? Czy mogę ustawić czas wygaśnięcia danych, które umieszczam w localStorage?

użytkownik280427
źródło
3
nie używaj localStorage, jeśli to możliwe, ponieważ nigdy nie wygasa automatycznie, tam możesz użyć sessionStorage, jest to bardziej
preferowane

Odpowiedzi:

215

Nie można określić terminu ważności. To zależy całkowicie od użytkownika.

https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage

Oczywiście możliwe jest, że coś, co aplikacja przechowuje na kliencie, może nie być później. Użytkownik może jawnie pozbyć się lokalnej pamięci lub przeglądarka może zostać wykorzystana w związku z przestrzenią. Dobrze jest programować defensywnie. Ogólnie jednak rzeczy pozostają „na zawsze” na podstawie praktycznej definicji tego słowa.

edytuj - oczywiście twoja aplikacja może aktywnie usuwać rzeczy, jeśli uzna, że ​​są za stare. Oznacza to, że możesz jawnie zawrzeć jakiś znacznik czasu w tym, co zostało zapisane, a następnie użyć go później, aby zdecydować, czy informacje powinny zostać usunięte.

Pointy
źródło
1
Czy więc użytkownik może liczyć na to, że dane będą dostępne po, powiedzmy, roku? Deweloper może liczyć na danych będących dostępne, chyba że użytkownik wyraźnie usuwa go?
Andres Riofrio
6
@AndresRiofrio Nie mogę znaleźć żadnej dokumentacji Mozilli, Microsoft lub W3C, która stanowiłaby jakiekolwiek obowiązkowe wygaśnięcie. Dlatego myślę, że odpowiedź brzmi: tak, agent użytkownika powinien przechowywać przechowywane dane do końca życia, lub dopóki użytkownik nie zażąda ich usunięcia (lub chyba dopóki twoja aplikacja nie usunie własnych).
Pointy
3
Oznacza to również, że Twoja przeglądarka stale się rozwija. Używasz aplikacji raz, przechowuje ona zawartość w przeglądarce i pozostaje tam na zawsze ....
Pieter van Kampen
1
Ilość danych localStorage, które możesz przechowywać na stronie wynosi około 10 MB, ale przeciętna strona nie przechowuje znacznie więcej niż kilku ciągów, więc nie miałbym nic przeciwko przestrzeni dyskowej
Juan
1
Firefox ma tutaj udokumentowaną politykę eksmisji .
ShreevatsaR
269

Sugerowałbym przechowywanie znacznika czasu w obiekcie przechowywanym w localStorage

var object = {value: "value", timestamp: new Date().getTime()}
localStorage.setItem("key", JSON.stringify(object));

Możesz parsować obiekt, uzyskać znacznik czasu i porównać z bieżącą datą, aw razie potrzeby zaktualizować wartość obiektu.

var object = JSON.parse(localStorage.getItem("key")),
    dateString = object.timestamp,
    now = new Date().getTime().toString();

compareTime(dateString, now); //to implement
sebarmeli
źródło
3
Cóż, nawet jeśli czas klienta nie jest spójny, nadal możesz znaleźć sposób wykorzystania czasu serwera. Jak echo znacznika czasu w div.
Supreme Dolphin
Czy analizowałbyś i porównywałeś znacznik czasu w przedziale czasu (np. settimoutCo 5 sekund) lub dla każdego żądania wysyłanego przez klienta do serwera?
ibubi
lepszym sposobem jest porównanie dat dla każdego żądania użytkownika
Terai
36

Możesz użyć lscache . Obsługuje to automatycznie, w tym przypadki, w których rozmiar pamięci przekracza limit. Jeśli tak się stanie, zacznie przycinać przedmioty, które są najbliżej ich określonego terminu ważności.

Z readme:

lscache.set

Stores the value in localStorage. Expires after specified number of minutes.

Arguments
key (string)
value (Object|string)
time (number: optional)

Jest to jedyna prawdziwa różnica między zwykłymi metodami przechowywania. Pobierz, usuń itp. Działają tak samo.

Jeśli nie potrzebujesz takiej funkcjonalności, możesz po prostu zapisać znacznik czasu z wartością (za pośrednictwem JSON) i sprawdzić, czy upłynął termin ważności.

Warto zauważyć, że istnieje dobry powód, dla którego lokalne przechowywanie należy do użytkownika. Ale rzeczy takie jak lscache przydają się, gdy trzeba przechowywać ekstremalnie tymczasowe dane.

huyz
źródło
Dziękuję Ci! To jest niesamowite, jeśli chodzi o to, czego potrzebuję - dane muszą tylko tam być, na wypadek, gdyby użytkownik zrobił booboo lub przeglądarka zamknęła się przed zapisaniem swojej pracy, ale jest za dużo danych na pliki cookie. Używam go w połączeniu z pieroxy.net/blog/pages/lz-string/index.html .
Peter Smartt,
34

Brynner Ferreira przyniósł dobry punkt: przechowywanie klucza rodzeństwa, w którym znajdują się informacje o wygaśnięciu. W ten sposób, jeśli masz dużą liczbę kluczy lub jeśli twoje wartości są dużymi obiektami Json , nie musisz ich analizować, aby uzyskać dostęp do znacznika czasu.

Oto ulepszona wersja:

 /*  removeStorage: removes a key from localStorage and its sibling expiracy key
    params:
        key <string>     : localStorage key to remove
    returns:
        <boolean> : telling if operation succeeded
 */
 function removeStorage(name) {
    try {
        localStorage.removeItem(name);
        localStorage.removeItem(name + '_expiresIn');
    } catch(e) {
        console.log('removeStorage: Error removing key ['+ key + '] from localStorage: ' + JSON.stringify(e) );
        return false;
    }
    return true;
}
/*  getStorage: retrieves a key from localStorage previously set with setStorage().
    params:
        key <string> : localStorage key
    returns:
        <string> : value of localStorage key
        null : in case of expired key or failure
 */
function getStorage(key) {

    var now = Date.now();  //epoch time, lets deal only with integer
    // set expiration for storage
    var expiresIn = localStorage.getItem(key+'_expiresIn');
    if (expiresIn===undefined || expiresIn===null) { expiresIn = 0; }

    if (expiresIn < now) {// Expired
        removeStorage(key);
        return null;
    } else {
        try {
            var value = localStorage.getItem(key);
            return value;
        } catch(e) {
            console.log('getStorage: Error reading key ['+ key + '] from localStorage: ' + JSON.stringify(e) );
            return null;
        }
    }
}
/*  setStorage: writes a key into localStorage setting a expire time
    params:
        key <string>     : localStorage key
        value <string>   : localStorage value
        expires <number> : number of seconds from now to expire the key
    returns:
        <boolean> : telling if operation succeeded
 */
function setStorage(key, value, expires) {

    if (expires===undefined || expires===null) {
        expires = (24*60*60);  // default: seconds for 1 day
    } else {
        expires = Math.abs(expires); //make sure it's positive
    }

    var now = Date.now();  //millisecs since epoch time, lets deal only with integer
    var schedule = now + expires*1000; 
    try {
        localStorage.setItem(key, value);
        localStorage.setItem(key + '_expiresIn', schedule);
    } catch(e) {
        console.log('setStorage: Error setting key ['+ key + '] in localStorage: ' + JSON.stringify(e) );
        return false;
    }
    return true;
}
Fernando Fabreti
źródło
W setStorage () nie powinna elsebyć linia expires = Math.abs(1000*expires); //make sure it's positive?
alissonmuller
Tylko punkt do getStoragerozmowy. Jeśli spróbujesz uzyskać _expiresInbezpośredni dostęp do wersji klucza, wówczas klucz staje się tym, ..._expiresIn_expiresInktóry oczywiście nie istnieje, więc usuwa oryginalny ..._expiresInklucz, a następnie przy następnym dostępie do oryginalnego klucza, ..._expiresInnie istnieje i usuwa oryginalny klucz. Sugerowałbym pułapkę za to, gdy natrafiłem na to w jednym z moich projektów. if(key.indexOf('_expiresIn') > -1) { return localStorage.getItem(key); }
akousmata
24

Chociaż lokalne przechowywanie nie zapewnia mechanizmu wygasania, pliki cookie to robią. Po prostu sparowanie lokalnego klucza pamięci z ciasteczkiem zapewnia prosty sposób na zapewnienie, że pamięć lokalna może zostać zaktualizowana o te same parametry wygasania, co ciasteczka.

Przykład w jQuery:

if (!$.cookie('your_key') || !localStorage.getItem('your_key')) {
    //get your_data from server, then...
    localStorage.setItem('your_key', 'your_data' );
    $.cookie('your_key', 1);
} else {
    var your_data = localStorage.getItem('your_key');
}
// do stuff with your_data

W tym przykładzie plik cookie z domyślnym parametrem wygasa po zamknięciu przeglądarki. Dlatego po zamknięciu i ponownym otwarciu przeglądarki lokalny magazyn danych dla twoich danych jest odświeżany przez wywołanie po stronie serwera.

Pamiętaj, że nie jest to dokładnie to samo, co usunięcie lokalnego magazynu danych, ale aktualizuje lokalny magazyn danych za każdym razem, gdy plik cookie wygasa. Jeśli jednak Twoim głównym celem jest możliwość przechowywania po stronie klienta więcej niż 4K (ograniczenie rozmiaru pliku cookie), ta para plików cookie i pamięci lokalnej pomoże Ci osiągnąć większy rozmiar pamięci przy użyciu tych samych parametrów wygasania jak plik cookie .

Robert Peake
źródło
Pliki cookie można usunąć, a co gorsza, można je całkowicie wyłączyć.
Supreme Dolphin
1
Najbardziej podoba mi się to rozwiązanie, ponieważ umożliwia przeglądarce obsługę wygaśnięcia naszego rozwiązania pamięci masowej bez konieczności korzystania z innych bibliotek lub ręcznego zarządzania lokalnymi datami przechowywania.
ecc
10
Pamiętaj, że pliki cookie są wysyłane na KAŻDĄ prośbę.
Lucas Freitas,
24

Tutaj wysoce zalecane jest użycie sessionStorage

  • jest taki sam jak localStorage, ale niszczy po zniszczeniu sesji / zamknięciu przeglądarki
  • także localStorage może współdzielić między kartami, podczas gdy sessionStorage może korzystać tylko z bieżącej karty, ale wartość nie zmienia się na stronie odświeżania ani nie zmienia strony
  • sessionStorage jest także przydatny w celu zmniejszenia ruchu sieciowego przeciwko plikom cookie

do użycia wartości zadanej

sessionStorage.setItem("key","my value");

dla uzyskania wartości wykorzystania

var value = sessionStorage.getItem("key");

kliknij tutaj, aby wyświetlić interfejs API

wszystkie sposoby zestawu są

  sessionStorage.key = "my val";
  sessionStorage["key"] = "my val";
  sessionStorage.setItem("key","my value");

wszystkie sposoby uzyskania są

  var value = sessionStorage.key;
  var value = sessionStorage["key"];
  var value = sessionStorage.getItem("key");
Dharmendrasinh Chudasama
źródło
8
Pamiętaj, że sessionStoragenie działa udostępnianie danych między kartami
Bhargava Mummadireddy
14

Cykl życia jest kontrolowany przez aplikację / użytkownika.

Od standardu :

Aplikacje klienckie powinny wygasać dane z lokalnych obszarów pamięci tylko ze względów bezpieczeństwa lub na żądanie użytkownika. Programy klienckie powinny zawsze unikać usuwania danych podczas działania skryptu, który ma dostęp do tych danych.

Jldupont
źródło
10

Z projektu W3C:

Aplikacje klienckie powinny wygasać dane z lokalnych obszarów pamięci tylko ze względów bezpieczeństwa lub na żądanie użytkownika. Programy klienckie powinny zawsze unikać usuwania danych podczas działania skryptu, który ma dostęp do tych danych.

Będziesz chciał dokonywać aktualizacji zgodnie z harmonogramem, używając setItem (klucz, wartość); spowoduje to dodanie lub aktualizację danego klucza o nowe dane.

FatherStorm
źródło
Hmm ... być może dobrym pomysłem byłoby podanie daty jako części danych? A może za pomocą innego klucza przy każdej zmianie danych.
DisgruntledGoat,
9
// Functions
function removeHtmlStorage(name) {
    localStorage.removeItem(name);
    localStorage.removeItem(name+'_time');
}

function setHtmlStorage(name, value, expires) {

    if (expires==undefined || expires=='null') { var expires = 3600; } // default: 1h

    var date = new Date();
    var schedule = Math.round((date.setSeconds(date.getSeconds()+expires))/1000);

    localStorage.setItem(name, value);
    localStorage.setItem(name+'_time', schedule);
}

function statusHtmlStorage(name) {

    var date = new Date();
    var current = Math.round(+date/1000);

    // Get Schedule
    var stored_time = localStorage.getItem(name+'_time');
    if (stored_time==undefined || stored_time=='null') { var stored_time = 0; }

    // Expired
    if (stored_time < current) {

        // Remove
        removeHtmlStorage(name);

        return 0;

    } else {

        return 1;
    }
}

// Status
var cache_status = statusHtmlStorage('cache_name');

// Has Data
if (cache_status == 1) {

    // Get Cache
    var data = localStorage.getItem('cache_name');
    alert(data);

// Expired or Empty Cache
} else {

    // Get Data
    var data = 'Pay in cash :)';
    alert(data);

    // Set Cache (30 seconds)
    if (cache) { setHtmlStorage('cache_name', data, 30); }

}
Brynner Ferreira
źródło
4
Podoba mi się to podejście, ponieważ nie wymaga ono najpierw analizy danych.
Christophe,
3

Jeśli ktoś używa wtyczki jStorage z jQuery, można dodać wygasanie za pomocą funkcji setTTL, jeśli wtyczka jStorage

$.jStorage.set('myLocalVar', "some value");
$.jStorage.setTTL("myLocalVar", 24*60*60*1000); // 24 Hr.
Amit
źródło
3

Jeśli ktoś nadal szuka szybkiego rozwiązania i nie chce zależności, takich jak jquery itp., Napisałem mini lib, który dodaje wygasanie do pamięci lokalnej / sesji / niestandardowej, możesz go znaleźć tutaj:

https://github.com/RonenNess/ExpiredStorage

Ronen Ness
źródło
3

Możesz spróbować tego.

var hours = 24; // Reset when storage is more than 24hours
var now = new Date().getTime();
var setupTime = localStorage.getItem('setupTime');
if (setupTime == null) {
     localStorage.setItem('setupTime', now)
} else {
    if(now-setupTime > hours*60*60*1000) {
         localStorage.clear()
         localStorage.setItem('setupTime', now);
    }
}
Jay Chauhan
źródło
1

Obejście problemu przy użyciu narzędzia kątowego i lokalnego:

angular.module('app').service('cacheService', function() {

  return {
    set: function(key, value, expireTimeInSeconds) {
      return localforage.setItem(key, {
        data: value,
        timestamp: new Date().getTime(),
        expireTimeInMilliseconds: expireTimeInSeconds * 1000
      })
    },
    get: function(key) {
      return localforage.getItem(key).then(function(item) {
        if(!item || new Date().getTime() > (item.timestamp + item.expireTimeInMilliseconds)) {
          return null
        } else {
          return item.data
        }
      })
    }
  }

})
Tomas Romero
źródło
Sprawdziłem witrynę i nie widzę żadnego klucza „expireTimeInMilliseconds” w interfejsie API. Czy to ustawienie nieudokumentowane / nieobsługiwane?
aaaaaa
1
@ PhilOlson to niestandardowa implementacja, której użyłem localforage. expireTimeInMillisecondsnie jest jakimś localforageatrybutem, ale zmienną, której użyłem do sprawdzenia, czy przechowywane dane muszą wygasnąć. Sprawdź getdefinicję funkcji na moim przykładzie.
Tomas Romero,
wow localforagenie jest lekką klasą pomocnika, której się spodziewałem
Simon_Weaver
1

Podejście @ sebarmeli jest moim zdaniem najlepsze, ale jeśli chcesz, aby dane były przechowywane przez cały czas trwania sesji, sessionStorageprawdopodobnie jest to lepsza opcja:

Jest to obiekt globalny (sessionStorage), który utrzymuje obszar pamięci dostępny przez czas trwania sesji strony. Sesja strony trwa tak długo, jak przeglądarka jest otwarta i przetrwa po przeładowaniu i przywróceniu strony. Otwarcie strony w nowej karcie lub oknie spowoduje zainicjowanie nowej sesji.

MDN: sessionStorage

Kevin Leary
źródło
1

Z korzyścią dla wyszukiwarek:

Podobnie jak Fernando, nie chciałem dodawać ładunku JSON, gdy przechowywane wartości były proste. Musiałem tylko śledzić niektóre interakcje w interfejsie użytkownika i dbać o to, by dane były odpowiednie (np. Jak użytkownik korzystał z witryny e-commerce przed sprawdzeniem).

Nie spełni to wszystkich kryteriów, ale mam nadzieję, że będzie to szybki start + kopiowanie i wklejanie dla kogoś i zapisanie dodawania kolejnej biblioteki.

UWAGA: Nie byłoby to dobre, gdybyś musiał odzyskać przedmioty indywidualnie.

// Addition
if(window.localStorage){
    localStorage.setItem('myapp-' + new Date().getTime(), 'my value');
}

// Removal of all expired items
if(window.localStorage){

    // two mins - (1000 * 60 * 20) would be 20 mins
    var expiryTime = new Date().getTime() - (1000 * 60 * 2);

    var deleteRows = [];
    for(var i=0; i < localStorage.length; i++){
        var key = localStorage.key(i);
        var partsArray = key.split('-');
        // The last value will be a timestamp
        var lastRow = partsArray[partsArray.length - 1];

        if(lastRow && parseInt(lastRow) < expiryTime){
            deleteRows.push(key);
        }
    }
    // delete old data
    for(var j=0; j < deleteRows.length; j++){
        localStorage.removeItem(deleteRows[j]);
    }
}
Hokej
źródło
0

Jeśli znasz obiekt locaStorage przeglądarki , wiesz, że nie ma możliwości zapewnienia czasu wygaśnięcia. Możemy jednak użyć Javascript, aby dodać TTL (czas życia), aby unieważnić elementy w locaStorage po upływie określonego czasu.

function setLocalStorage(key, value, ttl) {
    // `item` is an object which contains the original value
    // as well as the time when it's supposed to expire
    const item = {
        value: value,
        expiry: ttl <= 0 ? -1 : new Date().getTime() + ttl
    };
    localStorage.setItem(key, JSON.stringify(item));
}

function getLocalStorage(key) {
    const itemStr = localStorage.getItem(key);
    // if the item doesn't exist, return null
    if (!itemStr) {
        return null;
    }
    const item = JSON.parse(itemStr);
    // compare the expiry time of the item with the current time
    if (item.expiry > 0 && new Date().getTime() > item.expiry) {
        // If the item is expired, delete the item from storage
        // and return null
        localStorage.removeItem(key);
        return null;
    }
    return item.value;
}
iProDev
źródło