Пять вопросов для души localStorage. 5М? ? 10М!!!

внешний интерфейс JavaScript

Пять вопросов души

  1. Какая кодировка символов используется для ключей, хранящихся в localStorage
  2. Что такое единица измерения 5M?
  3. Занимает ли ключ localStorage место для хранения?
  4. Количество ключей в localStorage, влияние на производительность записи и чтения
  5. Напишите метод для подсчета используемого пространства в localStorage.

Мы отвечаем один за другим, а затем даем каждому интервьюеру еще один вопрос интервью.

我们常说localStorage存储空间是5M,请问这个5M的单位是什么?

Какая кодировка символов используется для ключей и значений, хранящихся в localStorage?

Открытый относительно авторитетный MDNlocalStorage#description

The keys and the values stored with localStorage are always in the UTF-16 DOMString format, which uses two bytes per character. As with objects, integer keys are automatically converted to strings.

перевести на китайский:

Ключи и значения, хранящиеся в localStorage, всегда имеют формат UTF-16 DOMString, используя два байта на символ. Как и объекты, целочисленные ключи автоматически преобразуются в строки.

Ответ: UTF-16.

Нет проблем с тем, что здесь описывает MDN, а есть проблемы, потому что UTF-16 использует два байта для каждого символа, есть предпосылки, то есть кодовая точка меньше0xFFFF(65535), а все, что больше этой кодовой точки, составляет четыре байта.

这是全文的关键。

Что такое единица измерения 5M?

Какова единица измерения 5M?

Опции:

  1. количество символов
  2. количество байтов
  3. значение длины символа
  4. Номер бита

Не знал, современные браузеры должны быть точнымиВариант 3, длина символов, илиВариант 5, блок кодирования utf-16

Количество символов не равно длине символов, вы должны это знать:

"a".length // 1
"人".length // 1
"𠮷".length // 2
"🔴".length // 2

Современные браузеры обрабатывают строки на основе UTF-16.DOMString.

Но длина строки 5M явно немного странная.

А по правилам кодировки UTF-16 либо 2 байта, либо четыре байта,所以不如说是 10M 的字节数,更为合理。

当然,2个字节作为一个utf-16的字符编码单元,也可以说是 5M 的utf-16的编码单元。

Давайте сначала напишем метод для подсчета количества байтов в строке utf-16: очень просто, определите, является ли кодовая точка 2 или 4

function sizeofUtf16Bytes(str) {
    var total = 0,
        charCode,
        i,
        len;
    for (i = 0, len = str.length; i < len; i++) {
        charCode = str.charCodeAt(i);
        if (charCode <= 0xffff) {
            total += 2;
        } else {
            total += 4;
        }
    }
    return total;
}

Давайте хранить до 10M байт

В качестве ключа оставляем 8 байтов, 8 байтов могут быть 4 символами, или 3 символами, кодовая точка которых больше 65535, или комбинацией.

Возможны следующие три комбинации:

  1. aaaa
  2. aa🔴
  3. 🔴🔴

Если на этой основе будет добавлен какой-либо символ, будет сообщено об исключении ошибки.

const charTxt = "人";
let count = (10 * 1024 * 1024 / 2) - 8 / 2;
let content = new Array(count).fill(charTxt).join("");
const key = "aa🔴";
localStorage.clear();
try {
    localStorage.setItem(key, content);
} catch (err) {
    console.log("err", err);
}

const sizeKey = sizeofUtf16Bytes(key);
const contentSize = sizeofUtf16Bytes(content);
console.log("key size:", sizeKey, content.length);
console.log("content size:", contentSize, content.length);
console.log("total size:", sizeKey + contentSize, content.length + key.length);

В случае современных браузеров:

Поэтому точнее и проще понять, что это количество байтов 10M.

Если вы говорите 5M, то его единицей является длина строки, а не количество символов.

Ответ: значение длины строки или единица кода utf-16.

更合理的答案是 10M字节空间。

Занимает ли ключ localStorage место для хранения?

Мы устанавливаем key и val на длину 2,5M соответственно.

const charTxt = "a";
let count = (2.5 * 1024 * 1024);
let content = new Array(count).fill(charTxt).join("");
const key = new Array(count).fill(charTxt).join("");
localStorage.clear();
try {
    console.time("setItem")
    localStorage.setItem(key, content);
    console.timeEnd("setItem")
} catch (err) {
    console.log("err code:", err.code);
    console.log("err message:", err.message)
}

Выполнить нормально.

Добавляем длину контента1, становится2.5 M + 1, длина ключа по-прежнему2.5Mдлина

const charTxt = "a";
let count = (2.5 * 1024 * 1024);
let content = new Array(count).fill(charTxt).join("") + 1;
const key = new Array(count).fill(charTxt).join("");
localStorage.clear();
try {
    console.time("setItem")
    localStorage.setItem(key, content);
    console.timeEnd("setItem")
} catch (err) {
    console.log("err code:", err.code);
    console.log("err message:", err.message)
}

image.png

Возникло исключение, и хранилище не удалось. Дополнительные сведения об исключении см.обнаружение localstorage_feature:

function storageAvailable(type) {
    var storage;
    try {
        storage = window[type];
        var x = '__storage_test__';
        storage.setItem(x, x);
        storage.removeItem(x);
        return true;
    }
    catch(e) {
        return e instanceof DOMException && (
            // everything except Firefox
            e.code === 22 ||
            // Firefox
            e.code === 1014 ||
            // test name field too, because code might not be present
            // everything except Firefox
            e.name === 'QuotaExceededError' ||
            // Firefox
            e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
            // acknowledge QuotaExceededError only if there's something already stored
            (storage && storage.length !== 0);
    }
}

Ответ: занимать место

Количество ключей, влияние на чтение и запись

нас500 * 1000ключ, как показано ниже

let keyCount = 500 * 1000;

localStorage.clear();
for (let i = 0; i < keyCount; i++) {
    localStorage.setItem(i, "");
}

setTimeout(() => {
    console.time("save_cost");
    localStorage.setItem("a", "1");
    console.timeEnd("save_cost");
}, 2000)


setTimeout(() => {
    console.time("read_cost");
    localStorage.getItem("a");
    console.timeEnd("read_cost");

}, 2000)

// save_cost: 0.05615234375 ms
// read_cost: 0.008056640625 ms

Вы выполняете только код сохранения:

localStorage.clear();    
console.time("save_cost");
localStorage.setItem("a", "1");
console.timeEnd("save_cost");
// save_cost: 0.033203125 ms

Его можно тестировать несколько раз, и влияние, безусловно, есть, но только несколько раз, не особенно большое.

И наоборот, что, если таблица хранимых значений больше?

const charTxt = "a";
const count = 5 * 1024 * 1024  - 1
const val1 = new Array(count).fill(charTxt).join("");

setTimeout(() =>{
    localStorage.clear();
    console.time("save_cost_1");
    localStorage.setItem("a", val1);
    console.timeEnd("save_cost_1");
},1000)


setTimeout(() =>{
    localStorage.clear();
    console.time("save_cost_2");
    localStorage.setItem("a", "a");
    console.timeEnd("save_cost_2");
},1000)

// save_cost_1: 12.276123046875 ms
// save_cost_2: 0.010009765625 ms

Это может быть проверено много раз Размер одного значения имеет большое влияние на производительность памяти, и то же самое верно для чтения, что разумно.

Поэтому старайтесь не сохранять большие значения, потому что это синхронное чтение, чистые большие данные, просто используйте indexedDB.

Ответ: Количество ключей влияет на скорость чтения, но не сильно. Размер значения больше влияет на производительность, поэтому не рекомендуется сохранять большие данные.

Напишите метод для подсчета используемого пространства в localStorage.

Маленькая версия для современных браузеров:

function sieOfLS() {
    return Object.entries(localStorage).map(v => v.join('')).join('').length;
}

Тестовый код:

localStorage.clear();
localStorage.setItem("🔴", 1);
localStorage.setItem("🔴🔴🔴🔴🔴🔴🔴🔴", 1111);
console.log("size:", sieOfLS())   // 23
// 🔴*9 + 1 *5 = 2*9 + 1*5 = 23

стандарт протокола html

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

Это не стандарт ES.

кодировка страницы utf-8

Наши html-страницы часто появляются <meta charset="UTF-8">. Сообщите браузеру, к какому формату кодировки символов принадлежит эта страница, и браузер выполнит декодирование на следующем шаге.

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>容器</title>
</head>

Это не имеет ничего общего с хранилищем localStorage.

расширение локального хранилища

Пространство localStorage составляет 10M байт, чего обычно достаточно, но у людей всегда есть жадность. Действительно достигнут лимит места, что делать?

Расширение LocalStorage — это отдельная тема.

напиши в конце

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

**Группа технического обмена, пожалуйста, перейдите наиди сюда. Или добавьте мое облако похорон WeChat и учитесь вместе.

Цитировать

localStorage