QuotaExceededError: Eccezione Dom 22: Tentativo di aggiungere qualcosa alla memoria che ha superato la quota


219

L'uso di LocalStorage su iPhone con iOS 7 genera questo errore. Ho cercato un risolutore, ma considerando che non sto nemmeno navigando in privato, nulla è rilevante.

Non capisco perché localStorage sia disabilitato per impostazione predefinita in iOS 7, ma sembra che lo sia? Ho testato anche su altri siti Web, ma senza fortuna. Ho anche provato a provarlo usando questo sito Web: http://arty.name/localstorage.html , ma non sembra che stia salvando nulla per qualche strana ragione.

Qualcuno ha avuto lo stesso problema, solo loro hanno avuto fortuna risolverlo? Devo cambiare il mio metodo di archiviazione?

Ho provato a eseguirne il debug archiviando solo poche righe di informazioni, ma senza risultati. Ho usato la localStorage.setItem()funzione standard per salvare.


2
Di solito significa che hai provato a memorizzare qualcosa con una dimensione che ha superato lo spazio di archiviazione disponibile. Quale browser stai utilizzando (Safari, Chrome, ecc.)? Riesci a condividere un po 'di più il codice che hai utilizzato e, se possibile, i dati che stai cercando di archiviare.

3
Questo dovrebbe essere considerato come un bug o un problema sul lato Safari. Non ha senso che non puoi utilizzare localStorage in modalità di navigazione in incognito ...
Maksim Luzik,

Utilizzare una funzione di rilevamento che verifica questo problema specifico . Se lo spazio di archiviazione non è disponibile, prendere in considerazione lo shunting localStorage con memoryStorage . disclaimer: sono l'autore dei pacchetti collegati
Stijn de Witt,

1
Nell'aprile 2017 una patch è stata fusa in Safari, quindi allineata con gli altri browser. Probabilmente atterrerà in Safari 11. bugs.webkit.org/show_bug.cgi?id=157010
sandstrom

2
Posso confermare che questo problema è stato risolto in Safari iOS 11. Testato Navigazione privata + sessionStorage.setItem () quindi sessionStorage.getItem () correttamente su iPhone6 ​​e iPhone8.
Kevin Gaudin,

Risposte:


372

Ciò può verificarsi quando Safari è in modalità di navigazione privata. Durante la navigazione privata, l'archiviazione locale non è affatto disponibile.

Una soluzione è avvisare l'utente che l'app ha bisogno della modalità non privata per funzionare.

AGGIORNAMENTO: questo problema è stato risolto in Safari 11 , quindi il comportamento è ora allineato con altri browser.


4
Il tuo post è stato incredibilmente utile e tempestivo per me oggi (meno di 24 ore dopo). Per riferimento, ecco come attivare / disattivare la navigazione privata: imore.com/how-use-private-browsing-ios-7-safari
Nick,

12
+1 risolto il mio problema. Stavo verificando l'esistenza di LocalStorage ( if( typeof Storage != 'undefined' ) { ... }) prima di provare a caricare e salvare informazioni ma ho riscontrato questo errore. Si scopre che Storageè ancora definito anche quando è inutilizzabile. Utilizzo di try / catch da ora in poi ogni volta che utilizzo LocalStorage.
Stevendesu,

Grazie! Strano errore di Safari. Avrebbe dovuto essere più informativo. : D
Sunny R Gupta,

2
Una correzione potrebbe essere in arrivo a partire da Safari Tech Preview 29: "Risolto QuotaExceededError durante il salvataggio in localStorage in modalità di navigazione privata o sessioni WebDriver". Vedi developer.apple.com/safari/technology-preview/release-notes
Marc Baumbach,

1
Ciò può verificarsi anche se viene raggiunto il limite di archiviazione che può essere facilmente eseguito salvando, ad esempio, le immagini.
csalmeida,

103

Come menzionato in altre risposte, otterrai sempre QuotaExceededError in modalità Browser privato Safari su iOS e OS X quando localStorage.setItem(o sessionStorage.setItem) viene chiamato.

Una soluzione consiste nell'eseguire un controllo try / catch o Modernizr in ciascuna istanza di utilizzo setItem.

Tuttavia, se si desidera uno shim che interrompa semplicemente questo errore a livello globale, per impedire la rottura del resto del JavaScript, è possibile utilizzare questo:

https://gist.github.com/philfreo/68ea3cd980d72383c951

// Safari, in Private Browsing Mode, looks like it supports localStorage but all calls to setItem
// throw QuotaExceededError. We're going to detect this and just silently drop any calls to setItem
// to avoid the entire page breaking, without having to do a check at each usage of Storage.
if (typeof localStorage === 'object') {
    try {
        localStorage.setItem('localStorage', 1);
        localStorage.removeItem('localStorage');
    } catch (e) {
        Storage.prototype._setItem = Storage.prototype.setItem;
        Storage.prototype.setItem = function() {};
        alert('Your web browser does not support storing settings locally. In Safari, the most common cause of this is using "Private Browsing Mode". Some settings may not save or some features may not work properly for you.');
    }
}

1
Perché aggiungere setItem all'oggetto Storage se non si riesce a usarlo comunque?
Negromante,

4
Il punto del mio frammento è semplicemente ignorare gli errori JS che vengono generati se desideri che la tua app non venga completamente rotta in modalità privata Safari.
philfreo,

16

Uso questa semplice funzione, che restituisce trueo false, per verificare la disponibilità di LocalStorage:

isLocalStorageNameSupported = function() {
    var testKey = 'test', storage = window.sessionStorage;
    try {
        storage.setItem(testKey, '1');
        storage.removeItem(testKey);
        return true;
    } catch (error) {
        return false;
    }
}

Ora puoi verificare la localStorage.setItem()disponibilità prima di usarlo. Esempio:

if ( isLocalStorageNameSupported() ) {
    // can use localStorage.setItem('item','value')
} else {
    // can't use localStorage.setItem('item','value')
}

Ho perso qualcosa? Perché è window.sessionStoragestato usato invece che window.localStorageper un metodo chiamato isLocalStorageNameSupported?
Ithar,

@lthar - vedi la documentazione qui: w3schools.com/html/html5_webstorage.asp Soprattutto questa parte:HTML local storage provides two objects for storing data on the client: window.localStorage - stores data with no expiration date window.sessionStorage - stores data for one session (data is lost when the browser tab is closed)
DrewT

@DrewT, ma qual è la differenza in questa situazione se si rimuove la chiave di prova? Non importa dove memorizzerò la mia chiave di prova se ho intenzione di eliminarla. Ho sbagliato? Perché l'archiviazione della sessione è migliore di quella locale?
Vladyslav Turak,

1
@TurakVladyslav hai ragione, non c'è davvero alcuna differenza qui, tranne che l'uso lo sessionStoragerende più gestibile per l'impostazione dei punti di interruzione se si desidera testare il proprio sviluppo. Non esiste un vero argomento per il quale sia "migliore" ed è davvero solo una preferenza personale qui che sbaglia dal lato della cautela. La cosa principale da notare è che entrambi sessionStoragee localStoragesono entrambe implementazioni dell'API di webstorage HTML5.
Estratto il

5

Mi è capitato di correre con lo stesso problema in iOS 7 (con alcuni dispositivi senza simulatori).

Sembra che Safari in iOS 7 abbia una quota di archiviazione inferiore, che a quanto pare è raggiunta con un registro cronologico lungo.

Immagino che la migliore pratica sarà quella di catturare l'eccezione.

Il progetto Modernizr ha una patch semplice, dovresti provare qualcosa di simile: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/storage/localstorage.js


3

Ecco una soluzione estesa basata sulla risposta di DrewT sopra che utilizza i cookie se localStorage non è disponibile. Utilizza la libreria docCookies di Mozilla :

function localStorageGet( pKey ) {
    if( localStorageSupported() ) {
        return localStorage[pKey];
    } else {
        return docCookies.getItem( 'localstorage.'+pKey );
    }
}

function localStorageSet( pKey, pValue ) {
    if( localStorageSupported() ) {
        localStorage[pKey] = pValue;
    } else {
        docCookies.setItem( 'localstorage.'+pKey, pValue );
    }
}

// global to cache value
var gStorageSupported = undefined;
function localStorageSupported() {
    var testKey = 'test', storage = window.sessionStorage;
    if( gStorageSupported === undefined ) {
        try {
            storage.setItem(testKey, '1');
            storage.removeItem(testKey);
            gStorageSupported = true;
        } catch (error) {
            gStorageSupported = false;
        }
    }
    return gStorageSupported;
}

Nella tua fonte, basta usare:

localStorageSet( 'foobar', 'yes' );
...
var foo = localStorageGet( 'foobar' );
...

2

Come già spiegato in altre risposte, in modalità Navigazione privata Safari genererà sempre questa eccezione quando si tenta di salvare i dati localStorage.setItem().

Per risolvere questo problema, ho scritto un localStorage falso che imita localStorage, sia metodi che eventi.

Archivio locale falso: https://gist.github.com/engelfrost/fd707819658f72b42f55

Questa probabilmente non è una buona soluzione generale al problema. Questa è stata una buona soluzione per il mio scenario, in cui l'alternativa consisterebbe in importanti riscritture su un'applicazione già esistente.


Cosa risolve esattamente? Non persiste nulla, quindi qual è il punto?
Esben Skov Pedersen,

1
"Risolve" Safari in modalità di navigazione privata. (Questo non è chiaro nella mia risposta, grazie per averlo sottolineato. Modificherò la mia risposta). Nulla dovrebbe essere persistito quando si è in modalità di navigazione privata a prescindere, quindi non persistere non è un problema rilevante qui. Ciò che questo risolto per me era consentire agli utenti di eseguire un'applicazione già esistente, senza importanti riscritture, anche quando si trovavano in modalità Navigazione privata in Safari.
Josef Engelfrost,

2

Aggiornamento (01/11/2016)

Stavo usando AmplifyJS menzionato di seguito per aggirare questo problema. Tuttavia, per Safari nella navigazione privata, stava ricadendo in una memoria basata sulla memoria. Nel mio caso, non era appropriato perché significa che l'archiviazione viene cancellata durante l'aggiornamento, anche se l'utente è ancora in navigazione privata.

Inoltre, ho notato un numero di utenti che navigano sempre in modalità privata su iOS Safari. Per tale motivo, un migliore fallback per Safari è l'uso dei cookie (se disponibili). Per impostazione predefinita, i cookie sono ancora accessibili anche nella navigazione privata. Naturalmente, vengono cancellati all'uscita dalla navigazione privata, ma non vengono cancellati all'aggiornamento.

Ho trovato la libreria local-storage-fallback . Dalla documentazione:

Scopo

Con le impostazioni del browser come "Navigazione privata" è diventato un problema fare affidamento su un window.localStorage funzionante, anche nei browser più recenti. Anche se può esistere, genererà eccezioni quando si tenta di utilizzare setItem o getItem. Questo modulo eseguirà i controlli appropriati per vedere quale meccanismo di archiviazione del browser potrebbe essere disponibile e quindi esporlo. Utilizza la stessa API di localStorage, quindi nella maggior parte dei casi dovrebbe funzionare come sostituzione drop-in.

Attenzione ai gotcha:

  • CookieStorage ha limiti di archiviazione. Stai attento qui.
  • MemoryStorage non persisterà tra i caricamenti di pagina. Questo è più o meno uno stop-gap per prevenire arresti anomali della pagina, ma può essere sufficiente per i siti Web che non eseguono il caricamento completo della pagina.

TL; DR:

Usa local-storage-fallback (API unificata con .getItem(prop)e .setItem(prop, val)):

Controllare e utilizzare l'adattatore di archiviazione appropriato per il browser (localStorage, sessionStorage, cookies, memory)

Risposta originale

Per aggiungere risposte precedenti, una possibile soluzione alternativa sarebbe quella di modificare il metodo di archiviazione. Ci sono alcune librerie come AmplifyJS e PersistJS che possono aiutare. Entrambe le librerie consentono l'archiviazione persistente sul lato client attraverso diversi backend.

Per AmplifyJS

memoria locale

  • IE 8+
  • Firefox 3.5+
  • Safari 4+
  • Cromo
  • Opera 10.5+
  • iPhone 2+
  • Android 2+

sessionStorage

  • IE 8+
  • Firefox 2+
  • Safari 4+
  • Cromo
  • Opera 10.5+
  • iPhone 2+
  • Android 2+

globalStorage

  • Firefox 2+

dati utente

  • IE 5 - 7
  • userData esiste anche nelle versioni più recenti di IE, ma a causa di stranezze nell'implementazione di IE 9, non registriamo userData se localStorage è supportato.

memoria

  • Un archivio in memoria viene fornito come fallback se nessuno degli altri tipi di archiviazione è disponibile.

Per PersistentJS

  • flash: memoria permanente Flash 8.
  • gears: archiviazione persistente basata su Google Gears.
  • localstorage: archiviazione bozze HTML5.
  • globalstorage: archiviazione bozze HTML5 (vecchie specifiche).
  • ovvero: comportamenti dei dati utente di Internet Explorer.
  • cookie: archiviazione persistente basata su cookie.

Offrono un livello di astrazione in modo da non doverti preoccupare di scegliere il tipo di archiviazione. Tieni presente che potrebbero esserci alcune limitazioni (come i limiti di dimensione) a seconda del tipo di archiviazione. In questo momento, sto usando AmplifyJS, ma devo ancora fare altri test su iOS 7 / Safari / ecc. per vedere se risolve effettivamente il problema.


Redattore John: Mi rendo conto che tu e Jonathan Alzetta siete probabilmente lo stesso account e state solo cercando di migliorare la vostra risposta, ma in tal caso dovreste davvero accedere come Jonathan Alzetta e modificare questa risposta, e poi non passerà attraverso la coda di revisione. Ripristina il tuo account, se necessario.
David


0

Questa domanda e risposta mi hanno aiutato a risolvere un problema specifico con l'iscrizione di nuovi utenti in Parse.

Poiché la funzione signUp (attrs, options) utilizza l'archiviazione locale per rendere persistente la sessione, se un utente è in modalità di navigazione privata, genera "QuotaExceededError: DOM Eccezione 22: è stato effettuato un tentativo di aggiungere qualcosa all'archiviazione che ha superato la quota". l'eccezione e le funzioni di successo / errore non vengono mai chiamate.

Nel mio caso, poiché la funzione di errore non viene mai chiamata, inizialmente sembrava essere un problema con l'attivazione dell'evento click sull'invio o il reindirizzamento definito in caso di successo dell'iscrizione.

Includere un avviso per gli utenti ha risolto il problema.

Parse Javascript SDK Reference https://parse.com/docs/js/api/classes/Parse.User.html#methods_signUp

Iscriviti un nuovo utente con un nome utente (o e-mail) e una password. Ciò creerà un nuovo Parse.User sul server e persisterà anche la sessione in localStorage in modo da poter accedere all'utente utilizzando {@link #current}.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.