Расчет использования пространства localStorage


80

Я создаю приложение, используя редактор Беспин и localStorage HTML5. Он хранит все файлы локально и помогает с грамматикой, использует JSLint и некоторые другие парсеры для CSS и HTML, чтобы помочь пользователю.

Я хочу подсчитать, какая часть лимита localStorage была использована и сколько на самом деле. Возможно ли это сегодня? Я думал не просто рассчитывать биты, которые хранятся. Но опять же, я не уверен, что еще я не могу измерить.



Полезные функции JavaScript / HTML5 localStorage: stackoverflow.com/q/34245593/4339170
CoderPi

Возможный дубликат Как найти размер localStorage
tripleee

Ответы:


73

Вы можете получить приблизительное представление, используя методы JSON для преобразования всего объекта localStorage в строку JSON:

JSON.stringify(localStorage).length

Я не знаю, насколько это будет с точностью до байта, особенно с несколькими байтами добавленной разметки, если вы используете дополнительные объекты, но я считаю, что это лучше, чем думать, что вы нажимаете только 28 КБ, а вместо этого делаете 280 КБ (или наоборот наоборот).


4
На самом деле это достаточно точно для работы. При максимальном уровне localStorage в Chrome 14 JSON.stringify (localStorage) .length === 2636625 или 2,51448 МБ, что достаточно близко ( dev-test.nemikor.com/web-storage/support-test ). Используется в тандеме с try {} catch {}, и у вас достаточно, чтобы создать вспомогательный класс.
Christopher

13
обратите внимание, что, как указано в тесте, который вы связываете, это размер в символах, а не в байтах: «Строки в JavaScript имеют кодировку UTF-16, поэтому для каждого символа требуется два байта памяти. Это означает, что, хотя многие браузеры имеют Ограничение в МБ, вы можете хранить только 2,5 млн символов ».
Mortimer

52

Я не нашел универсального способа получить оставшийся лимит для нужных мне браузеров, но я обнаружил, что при достижении лимита появляется сообщение об ошибке. Конечно, в каждом браузере это отличается.

Чтобы добиться максимума, я использовал этот небольшой скрипт:

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

Отсюда я получил эту информацию:

Гугл Хром

  • DOMException:
    • код: 22
    • сообщение: «Не удалось выполнить 'setItem' в 'Storage': установка значения 'data' превысила квоту».
    • имя: "QuotaExceededError"

Mozilla Firefox

  • DOMException:
    • код: 1014
    • сообщение: «Достигнут максимальный размер постоянного хранилища»
    • имя: "NS_ERROR_DOM_QUOTA_REACHED"

Сафари

  • DOMException:
    • код: 22
    • сообщение: «QuotaExceededError: DOM Exception 22»
    • имя: "QuotaExceededError"

Internet Explorer, Edge (сообщество)

  • DOMException:
    • код: 22
    • сообщение: "QuotaExceededError"
    • имя: "QuotaExceededError"

Мое решение

Пока что мое решение - добавлять дополнительный вызов каждый раз, когда пользователь что-либо сохраняет. И если будет обнаружено исключение, я скажу им, что у них заканчивается емкость хранилища.


Изменить: удалить добавленные данные

Я забыл упомянуть, что для того, чтобы это действительно работало, вам нужно удалить DATAэлемент, который был установлен изначально. Это изменение отражено выше с помощью функции removeItem () .


Очень хорошо, какова была ценность, iкогда это было достигнуто в каждом конкретном случае?
artlung

Думаю, 20-21. При желании вы можете запустить тест самостоятельно.
JeroenEijkhof,

IE: ABORT_ERR: 20 код: 22 сообщение: «QuotaExceededError» имя: «QuotaExceededError»
Руи Лима,

в IE ваш код вызывает исключение перед концом пробела: window.localStorage.remainingSpace: 805692 | window.localStorage.getItem ("ДАННЫЕ"). length: 4194304 | JSON.stringify (localStorage) .length: 4194315 | i: 22
Руи Лима

Хорошо, тогда я могу обернуть код локального хранилища в блоке try catch и предупредить пользователя в блоке catch о превышении размера.
Nirus

26

IE8 реализует remainingSpaceсвойство для этой цели:

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

К сожалению, похоже, что это недоступно в других браузерах. Однако я не уверен, реализуют ли они что-то подобное.


1
@WmasterJ: Я вижу, что команда IE фактически предложила включить это (или что-то подобное) в стандарт (еще в 2008 году): markmail.org/thread/ugzdcamtyftcyk6y .
Daniel Vassallo

45
На этот раз IE был прав. Казалось бы очевидным, что это необходимо.
JeroenEijkhof

Я не понимаю этого, - говорит Microsoft: «Атрибут localStorage обеспечивает постоянные области хранения для доменов. Он позволяет веб-приложениям хранить на клиенте почти 10 МБ пользовательских данных, таких как целые документы или почтовый ящик пользователя, из соображений производительности. " но в конце оставшееся пространство возвращает 5000000 (?!?!) почему ?!
Руи Лима

3
@RuiLima, обратите внимание, что поскольку символы в javascript используют два байта вместо одного, 5000000 символов фактически занимают 10 МБ места. Похоже, IE может сообщать оставшиеся символы вместо байтов, или они изменили свое мнение о пределе хранилища.
Ishmael Smyrnow

1
Это свойство unknownSpace важно, если вы ожидаете, что переполнение localStorage вызовет исключение: IE не выдаст его. Таким образом, вам необходимо проверить это свойство до и после попытки сохранения в localStorage. Если размер не изменился, значит, вы превысили свой лимит.
Энди

15

Вы можете использовать следующую строку, чтобы точно рассчитать это значение, а вот jsfiddle для иллюстрации его использования.

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

Я использую этот алгоритм для определения используемого пространства для расширения chrome, но я помню, как читал другой вопрос SO (забудьте, какой именно сейчас), что JS использует строки UTF-16 вместо UTF-8, и поэтому вам нужно удвоить количество байтов, которое вы получите, выполнив string.length. Вы знаете, правда ли это? Если так, мне придется обновить свой код ...
Адам Таттл,

1
ваш jsfiddle не загружается в моем браузере (mac / chrome).
Джастин

Похоже, вы сломали JSFiddle, хотя результат все еще можно увидеть здесь !
c24w

Разве вам не нужно умножать на 8, чтобы получить 8 байтов на символ или что-то в этом роде?
Джордж Мауэр

Джордж, в этом примере предполагается, что набор символов UTF-8 определен метатегом Content-Type на большинстве американских HTML-сайтов. Если вы хотите учесть поддержку юникода, загляните сюда mathiasbynens.be/notes/javascript-unicode Или для быстрого исправления вот функция, учитывающая поддержку юникода в JS github.com/craniumslows/Countable/commit/…
jas -

9

Попробовал сегодня во время тестирования (превышение квоты хранилища) и разработал решение. ИМО, знание того, каков предел и где мы находимся в отношениях, гораздо менее ценно, чем реализация функционального способа продолжения хранения сверх квоты.

Таким образом, вместо того, чтобы пытаться сравнивать размер и проверять емкость, давайте среагируем, когда мы достигнем квоты, уменьшим текущее хранилище на треть и возобновим сохранение. Если указанное сокращение не удалось, прекратите сохранение.

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

Эта функция находится внутри объекта-оболочки, поэтому public.set просто вызывает себя. Теперь мы можем увеличить объем хранилища и не беспокоиться о том, какая квота или насколько мы близки к ней. Если одно хранилище превышает 1/3, размер квоты - это то место, где эта функция перестанет отбраковывать и прекратит сохранение, и в этот момент вам все равно не следует кэшировать, верно?


5

Чтобы добавить к результатам теста браузера:

Firefox i = 22.

Safari версии 5.0.4 на моем Mac не зависает. Ошибка как Chrome. я = 21.

Opera сообщает пользователю, что веб-сайт хочет хранить данные, но на нем недостаточно места. Пользователь может отклонить запрос, увеличить лимит до требуемой суммы или до нескольких других лимитов или установить его на неограниченный. Зайдите в opera: webstorage, чтобы сказать, появляется это сообщение или нет. я = 20. Выведенная ошибка такая же, как и в Chrome.

Режим стандартов IE9 Ошибка как Chrome. я = 22.

IE9 в стандартном режиме IE8 Сообщение консоли «Ошибка: недостаточно памяти для выполнения этой операции». я = 22

IE9 в более старых режимах объектной ошибки. я = 22.

IE8 Нет копии для тестирования, но поддерживается локальное хранилище (http://stackoverflow.com/questions/3452816/does-ie8-support-out-of-the-box-in-localstorage)

IE7 и ниже Не поддерживает локальное хранилище.


3

Вы можете протестировать свой браузер с помощью этого теста поддержки веб-хранилища

Я тестировал Firefox как на своем планшете Android, так и на ноутбуке с Windows, а также Chromium только на результатах Windows:

  1. Firefox (windows):

    • localStorage : 5120 тыс. символов
    • sessionStorage : 5120k символов
    • localStorage : * не поддерживается
  2. Firefox (android):

    • localStorage : 2560 КБ символов
    • sessionStorage : Неограниченно (точно тест запускается до 10240k char == 20480k байт)
    • localStorage : не поддерживается
  3. Хром (windows):

    • localStorage : 5120 тыс. символов
    • sessionStorage : 5120k символов
    • localStorage : не поддерживается

Обновить

В Google Chrome версии 52.0.2743.116 м (64-разрядная версия) ограничения немного ниже для 5101kсимволов. Это означает, что максимальное количество доступных версий может меняться.


Вы brobably имел в виду 5120 K полукокса
Juribiyan

@Juribiyan Да, верю.
Мортеза Турани,

2

Хотел бы я добавить это в комментарий - недостаточно репутации, извините.

Я провел несколько тестов производительности - ожидал, что JSON.stringify (localStorage) .length будет дорогостоящей операцией при большой загруженности localStorage.

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

Это действительно так - примерно в 50 раз дороже, чем отслеживание того, что вы храните, и тем хуже, чем больше становится localStorage.


2

Эта функция получает точное доступное / оставшееся хранилище:

Я сделал набор полезных функций для localStorage * здесь *

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

Обратите внимание, что это не очень быстро, поэтому не используйте его все время.

При этом я также обнаружил, что: Item-Name будет занимать столько места, сколько его длина, Item-Value также будет занимать столько же места, сколько их длина.

Максимальный объем памяти, который у меня есть - всего около 5 МБ:

  • 5000000 символов - край
  • 5242880 символов - Хром
  • 5242880 символов - Firefox
  • 5000000 символов - IE

Вы найдете закомментированный код в скрипте, чтобы увидеть прогресс в консоли.

Мне потребовалось время, чтобы сделать, надеюсь, это поможет ☺


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

Мне нужно было фактически смоделировать и протестировать, что будет делать мой модуль, когда хранилище заполнено, поэтому мне нужно было получить точную точность, когда хранилище заполнено, а не принятый ответ, который теряет эту точность со скоростью i ^ 2.

Вот мой скрипт, который всегда должен давать точность 10 при достижении предела памяти и довольно быстро, несмотря на некоторые простые оптимизации ... EDIT: я сделал скрипт лучше и с точной точностью:

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

Это может кому-нибудь помочь. В chrome можно попросить пользователя разрешить использовать больше дискового пространства, если это необходимо:

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

Посетите https://developers.google.com/chrome/whitepapers/storage#asking_more для получения дополнительной информации.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.