Soul five q

  1. What character encoding is used for key values stored in localStorage
  2. What’s the unit of 5M
  3. The localStorage key occupies no storage space
  4. The number of localStorage keys affects the write and read performance
  5. Write a method to count the used space of a localStorage

We’ll answer them one by one, and then one more interview question for each interviewer.

We often say that localStorage storage space is 5M, what is the unit of 5M?

What character encoding is used for key values stored in localStorage?

Open the relative authority of MDN localStorage#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.

Translated into Chinese:

LocalStorage always stores keys and values in UTF-16 DOMString format with two bytes per character. Like objects, integer keys are automatically converted to strings.

Answer: UTF – 16

The MDN described here is fine and problematic, because UTF-16, which uses two bytes per character, has a condition that the code point is less than 0xFFFF(65535), and the code point larger than this is four bytes.

This is the crux of the text.

What’s the unit of 5M

What’s the unit of 5M?

Options:

  1. Number of characters
  2. The number of bytes
  3. The length value of a character
  4. Number of bits
  5. Utf-16 encoding unit

Previously unknown, modern browsers, the exact should be option 3, character length, or option 5, UTF-16 encoding unit

The number of characters does not equal the length of the characters.

"a".length / / 1
"People".length / / 1
"𠮷".length / / 2
"🔴".length / / 2
Copy the code

Modern browsers handle strings based on UTF-16 DOMString.

But the length of a 5M string is obviously a bit weird.

According to UTF-16 encoding rules, there are either 2 bytes or 4 bytes, so 10M bytes is more reasonable.

Of course, 2 bytes as a utf-16 character encoding unit, or 5M utf-16 encoding unit.

Let’s write a utF-16 string to calculate the number of bytes: very simple, determine whether the code point is 2 or 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;
}
Copy the code

We’re going to root out 10 megabytes for storage

We leave 8 bytes as the key, which is a normal 4 character swap, or 3 characters with a code point greater than 65535, or a combination.

The following three combinations are all possible,

  1. aaaa
  2. Aa 🔴
  3. 🔴 🔴

If any character is added to this, an error exception is reported.

const charTxt = "People";
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);
Copy the code

Modern browser cases:

So, 10M bytes is more accurate and easier to understand.

If you say 5M, the unit is the length of the string, not the number of characters.

Answer: the length value of the string, or the encoding unit of UTF-16

A more reasonable answer is 10M bytes of space.

The localStorage key occupies no storage space

Let’s make the key and val 2.5m long each

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)
}
Copy the code

The execution is normal.

We increase the length of the content by 1 to 2.5m + 1, and the key is still 2.5m long

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)
}
Copy the code

An exception occurs. Storage fails. Procedure For more details on exceptions, see LocalStorage_ Functional detection:

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); }}Copy the code

Answer: take up space

Number of keys, impact on read and write

We have 500 by 1000 bonds, as follows

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
Copy the code

You execute save code separately:

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

Can be tested many times, the impact is certainly some, is only several times, not particularly big.

Conversely, what if the saved value table is larger?

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
Copy the code

It can be tested many times, and the size of a single value has a huge impact on memory performance, as does reading, which makes sense.

So try not to store large values, because it is synchronous reading, pure big data, use indexedDB.

Answer: The number of keys has an effect on read performance, but not much. The value has a greater impact on performance. You are not advised to save large data.

Write a method to count the used space of a localStorage

Refined versions of modern browsers:

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

Test code:

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

HTML protocol standard

The LOCALStorage protocol of the WHATWG Technical Working Group on Hypertext Applications defines localstorage methods, properties, and so on, without specifying its storage space. As a result, the maximum limit varies from browser to browser.

It’s not the ES standard.

Utf-8 encoding of the page

often appears in our HTML pages. Tell the browser what character encoding format this page belongs to, and the next step is to decode the browser.

<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">Copy the code

This has nothing to do with localStorage.

LocalStorage capacity

LocalStorage space is 10M bytes, the general situation is enough, but people are always greedy. I really hit my space limit. How do I do that?

LocalStorage capacity expansion is a topic.

reference

localStorage