Obliczanie wykorzystania przestrzeni localStorage

80

Tworzę aplikację za pomocą edytora Bespin i localStorage HTML5. Przechowuje wszystkie pliki lokalnie i pomaga w gramatyce, używa JSLint i kilku innych parserów CSS i HTML, aby pomóc użytkownikowi.

Chcę obliczyć, jaka część limitu localStorage została wykorzystana i ile w rzeczywistości zostało. Czy jest to dziś możliwe? Myślałem, żeby nie po prostu obliczać przechowywanych bitów. Ale z drugiej strony nie jestem pewien, co więcej jest tego, czego nie potrafię zmierzyć.

JeroenEijkhof
źródło
JavaScript / HTML5 localStorage usefull Functions: stackoverflow.com/q/34245593/4339170
CoderPi
Możliwy duplikat Jak znaleźć rozmiar
localStorage

Odpowiedzi:

73

Możesz uzyskać przybliżony pomysł, używając metod JSON, aby zamienić cały obiekt localStorage na ciąg JSON:

JSON.stringify(localStorage).length

Nie wiem, jak dokładny byłby bajt, zwłaszcza z kilkoma bajtami dodanych znaczników, jeśli używasz dodatkowych obiektów - ale myślę, że to lepsze niż myślenie, że przesuwasz tylko 28 KB, a zamiast tego robisz 280 KB (lub vice- versa).

Morgon
źródło
4
Jest to wystarczająco dokładne, aby z nim pracować. Po maksymalnym wykorzystaniu localStorage w Chrome 14, JSON.stringify (localStorage) .length === 2636625 lub 2,51448 MB, czyli wystarczająco blisko ( dev-test.nemikor.com/web-storage/support-test ). Używane razem z try {} catch {} i masz wystarczająco dużo, aby zbudować klasę pomocniczą.
Christopher,
13
zwróć uwagę, że jak wskazano w teście, który łączysz, jest to rozmiar wyrażony w znakach, a nie w bajtach: „Łańcuchy w JavaScript to UTF-16, więc każdy znak wymaga dwóch bajtów pamięci. Oznacza to, że chociaż wiele przeglądarek ma 5 Limit MB, możesz przechowywać tylko 2,5 mln znaków. "
Mortimer
52

Nie znalazłem uniwersalnego sposobu na uzyskanie pozostałego limitu w przeglądarkach, których potrzebowałem, ale odkryłem, że po osiągnięciu limitu pojawia się komunikat o błędzie. W każdej przeglądarce jest to oczywiście inne.

Aby to osiągnąć, użyłem tego małego skryptu:

for (var i = 0, data = "m"; i < 40; i++) {
    try { 
        localStorage.setItem("DATA", data);
        data = data + data;
    } catch(e) {
        var storageSize = Math.round(JSON.stringify(localStorage).length / 1024);
        console.log("LIMIT REACHED: (" + i + ") " + storageSize + "K");
        console.log(e);
        break;
    }
}
localStorage.removeItem("DATA");

Stąd otrzymałem te informacje:

Google Chrome

  • DOMException:
    • kod: 22
    • komunikat: „Nie udało się wykonać„ setItem ”na„ Storage ”: Ustawienie wartości„ data ”przekroczyło limit."
    • name: "QuotaExceededError"

Mozilla Firefox

  • DOMException:
    • kod: 1014
    • komunikat: „Osiągnięto maksymalny rozmiar pamięci trwałej”
    • name: „NS_ERROR_DOM_QUOTA_REACHED”

Safari

  • DOMException:
    • kod: 22
    • message: „QuotaExceededError: DOM Exception 22”
    • name: "QuotaExceededError"

Internet Explorer, Edge (społeczność)

  • DOMException:
    • kod: 22
    • message: „QuotaExceededError”
    • name: "QuotaExceededError"

Moje rozwiązanie

Jak dotąd moim rozwiązaniem jest dodawanie dodatkowego połączenia za każdym razem, gdy użytkownik coś zapisał. A jeśli wyjątek zostanie przechwycony, powiedziałbym im, że kończy im się pojemność pamięci.


Edytuj: Usuń dodane dane

Zapomniałem wspomnieć, że aby to zadziałało, musisz usunąć DATApierwotnie ustawiony element. Zmiana jest odzwierciedlona powyżej za pomocą funkcji removeItem () .

JeroenEijkhof
źródło
Bardzo ładnie, jaka była wartość, ikiedy to zostało osiągnięte w każdym przypadku?
artlung
Myślę, że 20-21. Jeśli chcesz, możesz samodzielnie przeprowadzić test.
JeroenEijkhof
IE: ABORT_ERR: 20 code: 22 message: "QuotaExceededError" name: "QuotaExceededError"
Rui Lima
w IE twój kod zgłasza wyjątek przed końcem spacji: window.localStorage.remainingSpace: 805692 | window.localStorage.getItem ("DANE"). długość: 4194304 | JSON.stringify (localStorage) .length: 4194315 | f: 22
Rui Lima
dobrze, mogę zawinąć lokalny kod pamięci w bloku try catch i ostrzec użytkownika w bloku catch w przypadku przekroczenia rozmiaru.
Nirus
26

IE8 implementuje remainingSpacewłaściwość w tym celu:

alert(window.localStorage.remainingSpace);  // should return 5000000 when empty

Niestety wydaje się, że nie jest to dostępne w innych przeglądarkach. Nie jestem jednak pewien, czy realizują coś podobnego.

Daniel Vassallo
źródło
1
@WmasterJ: Widzę, że zespół IE faktycznie zaproponował włączenie tego (lub czegoś podobnego) do standardu (jeszcze w 2008): markmail.org/thread/ugzdcamtyftcyk6y .
Daniel Vassallo,
45
Tym razem IE miał rację. Wydawałoby się oczywiste, że jest to potrzebne.
JeroenEijkhof
Nie rozumiem tego, mówi Microsoft: „Atrybut localStorage zapewnia trwałe obszary pamięci dla domen. Umożliwia aplikacjom internetowym przechowywanie prawie 10 MB danych użytkownika, takich jak całe dokumenty lub skrzynka pocztowa użytkownika, na kliencie ze względu na wydajność. " ale na końcu pozostała spacja zwraca 5000000 (?!?!), dlaczego ?!
Rui Lima
3
@RuiLima, zwróć uwagę, że ponieważ znaki w javascript zajmują maksymalnie dwa bajty zamiast jednego, 5000000 znaków w rzeczywistości zajmuje 10 MB miejsca. Wygląda na to, że IE może zgłaszać pozostałe znaki zamiast bajtów lub zmienili zdanie na temat limitu pamięci.
Ishmael Smyrnow
1
Ta właściwość pozostałej przestrzeni jest ważna, jeśli spodziewasz się, że przepełnienie localStorage spowoduje zgłoszenie wyjątku: IE go nie zgłosi. Dlatego musisz sprawdzić tę właściwość przed i po próbie zapisania w localStorage. Jeśli rozmiar się nie zmienił, wiesz, że przekroczyłeś swój limit.
Andy,
15

Możesz użyć poniższej linii, aby dokładnie obliczyć tę wartość, a tutaj znajduje się jsfiddle, aby zilustrować jej użycie

alert(1024 * 1024 * 5 - escape(encodeURIComponent(JSON.stringify(localStorage))).length);
jas-
źródło
Używam tego algorytmu do określenia zajętego miejsca na rozszerzenie chrome, ale pamiętam, że czytałem inne pytanie SO (zapomnij teraz, które z nich), że JS używa ciągów UTF-16 zamiast UTF-8 i jako takie musisz podwoić liczbę bajtów, które uzyskasz wykonując string.length. Czy wiesz, czy to prawda? Jeśli tak, będę musiał zaktualizować mój kod ...
Adam Tuttle
1
twój jsfiddle nie ładuje się w mojej przeglądarce (Mac / Chrome).
Justin
Wygląda na to, że zepsułeś JSFiddle, chociaż nadal możesz zobaczyć wyniki tutaj !
c24w
Nie musisz mnożyć przez 8 dla 8 bajtów na znak czy coś w tym rodzaju?
George Mauer
George, ten przykład zakłada zestaw znaków UTF-8 zdefiniowany przez metatag „Content-Type” w większości witryn HTML w USA. Jeśli chcesz wziąć pod uwagę obsługę Unicode, zajrzyj tutaj mathiasbynens.be/notes/javascript-unicode Lub dla szybkiej poprawki tutaj jest funkcja uwzględniająca obsługę Unicode w JS github.com/craniumslows/Countable/commit/ ...
jas -
9

Wpadłem na to dzisiaj podczas testowania (przekraczając limit miejsca) i przygotowałem rozwiązanie. IMO, wiedząc, jaki jest limit i gdzie jesteśmy w stosunku, jest znacznie mniej wartościowe niż wdrożenie funkcjonalnego sposobu na dalsze przechowywanie poza limitem.

Dlatego zamiast próbować porównywać rozmiary i sprawdzać pojemność, reagujmy, gdy osiągniemy limit, zmniejszamy naszą obecną pamięć o jedną trzecią i wznawiamy przechowywanie. Jeśli wspomniana redukcja się nie powiedzie, przestań przechowywać.

set: function( param, val ) { 
    try{
        localStorage.setItem( param, typeof value == 'object' ? JSON.stringify(value) : value )
        localStorage.setItem( 'lastStore', new Date().getTime() )
    }
    catch(e){
      if( e.code === 22 ){
        // we've hit our local storage limit! lets remove 1/3rd of the entries (hopefully chronologically)
        // and try again... If we fail to remove entries, lets silently give up
        console.log('Local storage capacity reached.')

        var maxLength = localStorage.length
          , reduceBy = ~~(maxLength / 3);

        for( var i = 0; i < reduceBy; i++ ){
          if( localStorage.key(0) ){
            localStorage.removeItem( localStorage.key(0) );
          }
          else break;
        }

        if( localStorage.length < maxLength ){
          console.log('Cache data reduced to fit new entries. (' + maxLength + ' => ' + localStorage.length + ')');
          public.set( param, value );
        }
        else {
          console.log('Could not reduce cache size. Removing session cache setting from this instance.');
          public.set = function(){}
        }
      }
    }
}

Ta funkcja znajduje się w obiekcie opakowującym, więc public.set po prostu wywołuje samą siebie. Teraz możemy dodać miejsce do przechowywania i nie martwić się, jaki jest przydział ani jak blisko jesteśmy. Jeśli pojedynczy sklep przekracza 1/3, wielkość przydziału to miejsce, w którym ta funkcja przestanie wybierać i zakończy przechowywanie, a w tym momencie nie powinieneś i tak buforować, prawda?

But
źródło
5

Aby dodać do wyników testu przeglądarki:

Firefox i = 22.

Safari w wersji 5.0.4 na moim Macu nie zawiesiło się. Błąd jako Chrome. i = 21.

Opera informuje użytkownika, że ​​witryna chce przechowywać dane, ale nie ma wystarczająco dużo miejsca. Użytkownik może odrzucić wniosek, zwiększyć limit do wymaganej kwoty lub do kilku innych limitów lub ustawić go na nieograniczony. Idź do opera: webstorage, aby powiedzieć, czy ta wiadomość się pojawi, czy nie. i = 20. Zgłoszony błąd jest taki sam jak w Chrome.

Tryb standardów IE9 Błąd jako Chrome. i = 22.

Przeglądarka IE9 w trybie standardów IE8 Komunikat konsoli „Błąd: za mało miejsca na wykonanie tej operacji”. i = 22

IE9 w starszych trybach błąd obiektu. i = 22.

IE8 Nie mam kopii do przetestowania, ale pamięć lokalna jest obsługiwana (http://stackoverflow.com/questions/3452816/does-ie8-support-out-of-the-box-in-localstorage)

IE7 i starsze Nie obsługuje pamięci lokalnej.

user535673
źródło
3

Możesz przetestować swoją przeglądarkę za pomocą tego testu obsługi magazynu internetowego

Przetestowałem Firefoksa zarówno na moim tablecie z Androidem, jak i laptopie z systemem Windows oraz Chromium tylko w wynikach Windows:

  1. Firefox (Windows):

    • localStorage : 5120k char
    • sessionStorage : 5120k char
    • localStorage : * nieobsługiwane
  2. Firefox (Android):

    • localStorage : 2560k char
    • sessionStorage : Unlimited (dokładnie przebiegi testowe do 10240 k znaków == 20480 k bajtów)
    • localStorage : nieobsługiwane
  3. Chrom (Windows):

    • localStorage : 5120k char
    • sessionStorage : 5120k char
    • localStorage : nieobsługiwane

Aktualizacja

W przeglądarce Google Chrome w wersji 52.0.2743.116 m (64-bitowe) limity są nieco niższe dla 5101kznaków. Oznacza to, że maksymalna dostępna liczba może ulec zmianie w wersjach.

Morteza Tourani
źródło
Bez wątpienia miałeś na myśli 5120 k char
Juribiyan
@Juribiyan Yes I do.
Morteza Tourani
2

Chciałbym móc to dodać w komentarzu - za mało przedstawiciela, przepraszam.

Przeprowadziłem kilka testów perf - spodziewając się, że JSON.stringify (localStorage) .length będzie kosztowną operacją przy dużym obłożeniu localStorage.

http://jsperf.com/occupied-localstorage-json-stringify-length

Rzeczywiście tak jest - około 50 razy droższe niż śledzenie tego, co przechowujesz, i pogarsza się, im pełniejsza jest pamięć lokalna.

SashaK
źródło
2

Ta funkcja pobiera dokładną dostępną / pozostałą pamięć:

Zrobiłem zestaw przydatnych funkcji dla localStorage * tutaj *

http://jsfiddle.net/kzq6jgqa/3/

function getLeftStorageSize() {
    var itemBackup = localStorage.getItem("");
    var increase = true;
    var data = "1";
    var totalData = "";
    var trytotalData = "";
    while (true) {
        try {
            trytotalData = totalData + data;
            localStorage.setItem("", trytotalData);
            totalData = trytotalData;
            if (increase) data += data;
        } catch (e) {
            if (data.length < 2) break;
            increase = false;
            data = data.substr(data.length / 2);
        }
    }
    localStorage.setItem("", itemBackup);

    return totalData.length;
}

// Examples
document.write("calculating..");
var storageLeft = getLeftStorageSize();
console.log(storageLeft);
document.write(storageLeft + "");

// to get the maximum possible *clear* the storage 
localStorage.clear();
var storageMax = getLeftStorageSize();

Pamiętaj, że nie jest to bardzo szybkie, więc nie używaj go cały czas.

Dzięki temu dowiedziałem się również, że: nazwa przedmiotu zajmie tyle miejsca, ile jego długość, wartość przedmiotu również zajmie tyle miejsca, ile ich długość.

Maksymalne miejsce, które mam - wszystko około 5M:

  • 5000000 znaków - Edge
  • 5242880 znaków - Chrome
  • 5242880 znaków - Firefox
  • 5000000 znaków - IE

Na skrzypcach znajdziesz kod z komentarzem, aby zobaczyć postęp w konsoli.

Zajęło mi to trochę czasu, mam nadzieję, że to pomoże ☺

CoderPi
źródło
2
 try {
     var count = 100;
     var message = "LocalStorageIsNOTFull";
     for (var i = 0; i <= count; count + 250) {
         message += message;
         localStorage.setItem("stringData", message);
         console.log(localStorage);
         console.log(count);
     }

 }
 catch (e) {
     console.log("Local Storage is full, Please empty data");
     // fires When localstorage gets full
     // you can handle error here ot emply the local storage
 }
jinal
źródło
1

Musiałem faktycznie zasymulować i przetestować, co zrobi mój moduł, gdy pamięć jest pełna, więc musiałem uzyskać dokładną dokładność, kiedy pamięć jest pełna, a nie akceptowaną odpowiedź, która traci tę precyzję w tempie i ^ 2.

Oto mój skrypt, który powinien zawsze dawać precyzję 10 po osiągnięciu limitu pamięci i dość szybko, pomimo kilku łatwych optymalizacji ... EDYCJA: Poprawiłem skrypt z dokładną precyzją:

function fillStorage() {
    var originalStr = "1010101010";
    var unfold = function(str, times) {
        for(var i = 0; i < times; i++)
            str += str;
        return str;
    }
    var fold = function(str, times) {
        for(var i = 0; i < times; i++) {
            var mid = str.length/2;
            str = str.substr(0, mid);
        }
        return str;
    }

    var runningStr = originalStr;
    localStorage.setItem("filler", runningStr);
    while(true) {
        try {
            runningStr = unfold(runningStr, 1);
            console.log("unfolded str: ", runningStr.length)
            localStorage.setItem("filler", runningStr);
        } catch (err) {
            break;
        }
    }

    runningStr = fold(runningStr, 1);  
    var linearFill = function (str1) {
        localStorage.setItem("filler", localStorage.getItem("filler") + str1);
    }
    //keep linear filling until running string is no more...
    while(true) {
        try {
            linearFill(runningStr)
        } catch (err) {
            runningStr = fold(runningStr, 1);
            console.log("folded str: ", runningStr.length)
            if(runningStr.length == 0)
                break;
        }
    }

    console.log("Final length: ", JSON.stringify(localStorage).length)
}
balthatrix
źródło
0

To może komuś pomóc. W chrome można poprosić użytkownika o zezwolenie na użycie większej ilości miejsca na dysku w razie potrzeby:

// Request Quota (only for File System API)  
window.webkitStorageInfo.requestQuota(PERSISTENT, 1024*1024, function(grantedBytes) {
  window.webkitRequestFileSystem(PERSISTENT, grantedBytes, onInitFs, errorHandler); 
}, function(e) {
  console.log('Error', e); 
});

Odwiedź https://developers.google.com/chrome/whitepapers/storage#asking_more, aby uzyskać więcej informacji.

Remo H. Jansen
źródło