Cálculo del uso del espacio de almacenamiento local


80

Estoy creando una aplicación usando el editor Bespin y localStorage de HTML5. Almacena todos los archivos localmente y ayuda con la gramática, utiliza JSLint y algunos otros analizadores de CSS y HTML para ayudar al usuario.

Quiero calcular cuánto del límite de almacenamiento local se ha utilizado y cuánto hay realmente. ¿Es esto posible hoy? Estaba pensando en no simplemente calcular los bits que se almacenan. Pero, de nuevo, no estoy seguro de qué más hay que no pueda medir yo mismo.



Funciones útiles de JavaScript / HTML5 localStorage: stackoverflow.com/q/34245593/4339170
CoderPi

Respuestas:


73

Es posible que pueda obtener una idea aproximada utilizando los métodos JSON para convertir todo el objeto localStorage en una cadena JSON:

JSON.stringify(localStorage).length

No sé qué tan preciso en bytes sería, especialmente con los pocos bytes de marcado agregado si está usando objetos adicionales, pero creo que es mejor que pensar que solo está presionando 28K y en su lugar haciendo 280K (o viceversa) versa).


4
Esto es lo suficientemente preciso para trabajar. Con localStorage al máximo en Chrome 14, JSON.stringify (localStorage) .length === 2636625 o 2.51448 MB, que es lo suficientemente cercano ( dev-test.nemikor.com/web-storage/support-test ). Se usa en conjunto con try {} catch {}, y tienes suficiente para crear una clase de ayuda.
Christopher

13
tenga en cuenta que, como se señaló en la prueba que vincula, este es un tamaño en caracteres y no en bytes: "Las cadenas en JavaScript son UTF-16, por lo que cada carácter requiere dos bytes de memoria. Esto significa que, si bien muchos navegadores tienen 5 Límite de MB, solo puede almacenar 2,5 millones de caracteres ".
Mortimer

52

No encontré una forma universal de obtener el límite restante en los navegadores que necesitaba, pero descubrí que cuando alcanzas el límite, aparece un mensaje de error. Por supuesto, esto es diferente en cada navegador.

Para maximizarlo, usé este pequeño script:

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");

De eso obtuve esta información:

Google Chrome

  • DOMException:
    • código: 22
    • mensaje: "No se pudo ejecutar 'setItem' en 'Almacenamiento': la configuración del valor de 'datos' excedió la cuota".
    • nombre: "QuotaExceededError"

Mozilla Firefox

  • DOMException:
    • código: 1014
    • mensaje: "Se alcanzó el tamaño máximo de almacenamiento persistente"
    • nombre: "NS_ERROR_DOM_QUOTA_REACHED"

Safari

  • DOMException:
    • código: 22
    • mensaje: "QuotaExceededError: DOM Exception 22"
    • nombre: "QuotaExceededError"

Internet Explorer, Edge (comunidad)

  • DOMException:
    • código: 22
    • mensaje: "QuotaExceededError"
    • nombre: "QuotaExceededError"

Mi solución

Hasta ahora, mi solución es agregar una llamada adicional cada vez que el usuario guarda algo. Y si se detecta la excepción, les diría que se están quedando sin capacidad de almacenamiento.


Editar: eliminar los datos agregados

Olvidé mencionar que para que esto realmente funcione, necesitaría eliminar el DATAelemento que se configuró originalmente. El cambio se refleja arriba usando la función removeItem () .


Muy bonito, ¿cuál fue el valor de icuándo se alcanzó en cada caso?
artlung

20-21 creo. Puede ejecutar la prueba usted mismo si lo desea.
JeroenEijkhof

IE: ABORT_ERR: 20 código: 22 mensaje: "QuotaExceededError" nombre: "QuotaExceededError"
Rui Lima

en IE su código genera una excepción antes del fin del espacio: window.localStorage.remainingSpace: 805692 | window.localStorage.getItem ("DATOS"). longitud: 4194304 | JSON.stringify (localStorage) .length: 4194315 | i: 22
Rui Lima

Bueno, entonces puedo envolver el código de almacenamiento local en el bloque try catch y alertar al usuario en el bloque catch sobre el tamaño superior.
Nirus

26

IE8 implementa la remainingSpacepropiedad para este propósito:

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

Desafortunadamente, parece que esto no está disponible en los otros navegadores. Sin embargo, no estoy seguro de si implementan algo similar.


1
@WmasterJ: Veo que el equipo de IE propuso que esto (o algo similar) se incluyera en el estándar (en 2008): markmail.org/thread/ugzdcamtyftcyk6y .
Daniel Vassallo

45
Esta vez IE tenía razón. Parecería obvio que esto es necesario.
JeroenEijkhof

No entiendo esto, dice Microsoft: "El atributo localStorage proporciona áreas de almacenamiento persistentes para dominios. Permite que las aplicaciones web almacenen casi 10 MB de datos de usuario, como documentos completos o el buzón de correo de un usuario, en el cliente por razones de rendimiento. " pero al final el espacio restante devuelve 5000000 (?!?!) ¡¿Por qué ?!
Rui Lima

3
@RuiLima, tenga en cuenta que debido a que los caracteres en javascript usan dos bytes en lugar de uno, 5000000 caracteres en realidad ocupan 10 MB de espacio. Parece que IE puede estar informando caracteres restantes, en lugar de bytes, o cambiaron de opinión sobre el límite de almacenamiento.
Ishmael Smyrnow

1
Esta propiedad residentSpace es importante si espera que su desbordamiento de localStorage arroje una excepción: IE no lanzará una. Por lo tanto, debe verificar esta propiedad antes y después de intentar guardar en localStorage. Si el tamaño no ha cambiado, sabe que ha superado su límite.
Andy

15

Puede usar la siguiente línea para calcular con precisión este valor y aquí hay un jsfiddle para ilustrar su uso

alert(1024 * 1024 * 5 - escape(encodeURIComponent(JSON.stringify(localStorage))).length);

Estoy usando este algoritmo para determinar el espacio usado para una extensión de Chrome, pero recuerdo haber leído otra pregunta SO (olvide cuál, ahora) que JS usa cadenas UTF-16 en lugar de UTF-8, y como tal, debe duplicar la cantidad de bytes que obtienes al hacer string.length. ¿Sabes si eso es cierto? Si es así, tendré que actualizar mi código ...
Adam Tuttle

1
su jsfiddle no se carga en mi navegador (mac / chrome).
Justin

Parece que rompiste JSFiddle, ¡aunque todavía puedes ver el resultado aquí !
c24w

¿No tienes que multiplicar por 8 por 8 bytes por carácter o algo así?
George Mauer

George, ese ejemplo asume un juego de caracteres UTF-8 según lo definido por la metaetiqueta 'Content-Type' en la mayoría de los sitios HTML de EE. UU. Si desea tener en cuenta la compatibilidad con Unicode, eche un vistazo aquí mathiasbynens.be/notes/javascript-unicode O para la solución rápida, aquí hay una función para tener en cuenta la compatibilidad con Unicode en JS github.com/craniumslows/Countable/commit/…
jas -

9

Me encontré con esto hoy mientras probaba (excediendo la cuota de almacenamiento) y preparé una solución. En mi opinión, saber cuál es el límite y dónde estamos en relación es mucho menos valioso que implementar una forma funcional de continuar almacenando más allá de la cuota.

Por lo tanto, en lugar de intentar hacer comparaciones de tamaño y verificaciones de capacidad, reaccionaremos cuando alcancemos la cuota, reduzcamos nuestro almacenamiento actual en un tercio y reanudemos el almacenamiento. Si dicha reducción falla, deja de almacenar.

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(){}
        }
      }
    }
}

Esta función vive dentro de un objeto contenedor, por lo que public.set simplemente se llama a sí mismo. Ahora podemos agregar almacenamiento y no preocuparnos de cuál es la cuota o qué tan cerca estamos de ella. Si una sola tienda excede 1/3 del tamaño de la cuota es donde esta función dejará de seleccionar y dejará de almacenar, y en ese punto, no debería estar almacenando en caché de todos modos, ¿verdad?


5

Para agregar a los resultados de la prueba del navegador:

Firefox i = 22.

Safari versión 5.0.4 en mi Mac no se bloqueó. Error como Chrome. i = 21.

Ópera Le dice al usuario que el sitio web quiere almacenar datos pero no tiene suficiente espacio. El usuario puede rechazar la solicitud, hasta el límite de la cantidad requerida o varios otros límites, o establecerlo como ilimitado. Vaya a opera: webstorage para decir si este mensaje aparece o no. i = 20. El error arrojado es el mismo que el de Chrome.

Modo de estándares IE9 Error del como Chrome. yo = 22.

IE9 en modo estándar IE8 Mensaje de consola "Error: no hay suficiente almacenamiento disponible para completar esta operación". i = 22

IE9 en modos anteriores error de objeto. yo = 22.

IE8 No tiene una copia para probar, pero el almacenamiento local es compatible (http://stackoverflow.com/questions/3452816/does-ie8-support-out-of-the-box-in-localstorage)

IE7 y versiones anteriores No admite almacenamiento local.


3

Puede probar su navegador con esta prueba de soporte de almacenamiento web

Probé Firefox tanto en mi tableta Android como en mi computadora portátil con Windows y Chromium solo en los resultados de Windows:

  1. Firefox (Windows):

    • almacenamiento local : 5120k caracteres
    • sessionStorage : 5120k char
    • localStorage : * no compatible
  2. Firefox (Android):

    • localStorage : 2560k char
    • sessionStorage : Ilimitado (exactamente la prueba se ejecuta hasta 10240k char == 20480k byte)
    • localStorage : no compatible
  3. Cromo (ventanas):

    • almacenamiento local : 5120k caracteres
    • sessionStorage : 5120k char
    • localStorage : no compatible

Actualizar

En la versión de Google Chrome 52.0.2743.116 m (64 bits) los límites eran un poco más bajos en 5101kcaracteres. Esto significa que el máximo disponible puede cambiar en las versiones.


Probablemente quisiste decir 5120 k char
Juribiyan

@Juribiyan Sí, lo hago.
Morteza Tourani

2

Ojalá pudiera agregar esto en un comentario, no hay suficiente representante, lo siento.

Ejecuté algunas pruebas de rendimiento, esperando que JSON.stringify (localStorage) .length fuera una operación costosa en una gran ocupación de localStorage.

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

De hecho, es así: aproximadamente 50 veces más caro que realizar un seguimiento de lo que está almacenando, y empeora cuanto más se llena el almacenamiento local.


2

Esta función obtiene el almacenamiento exacto disponible / restante:

Hice un conjunto de funciones útiles para localStorage * aquí *

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();

Tenga en cuenta que esto no es muy rápido, así que no lo use todo el tiempo.

Con esto también descubrí que: el Item-Name ocupará tanto espacio como su longitud, el Item-Value también ocupará tanto espacio como su longitud.

Almacenamiento máximo que tengo, todo alrededor de 5 M:

  • 5000000 caracteres - Borde
  • 5242880 caracteres - Chrome
  • 5242880 caracteres - Firefox
  • 5000000 caracteres - IE

Encontrará un código con comentarios en el violín para ver el progreso en la consola.

Me tomó algo de tiempo hacerlo, espero que esto ayude ☺


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
 }

1

Necesitaba simular y probar realmente lo que haría mi módulo cuando el almacenamiento está lleno, por lo que necesitaba obtener una precisión cercana sobre cuándo el almacenamiento está lleno, en lugar de la respuesta aceptada, que pierde esa precisión a una velocidad de i ^ 2.

Aquí está mi guión, que siempre debería producir una precisión de 10 cuando se alcanza el límite de memoria, y bastante rápido a pesar de tener algunas optimizaciones fáciles ... EDITAR: Hice el guión mejor y con una precisión exacta:

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)
}

0

Esto podría ayudar a alguien. En Chrome es posible pedirle al usuario que permita usar más espacio en disco si es necesario:

// 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); 
});

Visite https://developers.google.com/chrome/whitepapers/storage#asking_more para obtener más información.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.