localStorage值的最大大小是多少?

702

因为目前localStorage只支持字符串类型的值,而为了实现这个,对象需要被转换成字符串(JSON-string)格式,然后才能进行存储。那么,关于值的长度是否有限制,是否有适用于所有浏览器的定义呢?

是否有人知道这个问题的答案?


27
我认为实际上没有人回答“每个值的最大长度”这个问题。 - Pete Alvin
2
@PeteAlvin 我刚刚回答了这个问题 - user2428118
6
所有浏览器:https://www.html5rocks.com/en/tutorials/offline/quota-research/(原文链接) - MCCCS
2
@PeteAlvin 有人在2015年回答了这个问题。其他答案涉及总大小的限制,但没有涉及每个值的大小限制。 - Ali
1
我创建了这个 Code Sandbox 来测试我的限制(5MB),如果有人感兴趣: https://codesandbox.io/s/localstorage-capacity-cillxb?file=/src/index.js - Yanick Rochon
13个回答

507

引用自维基百科关于Web Storage的文章:

可以简单地将Web Storage视为Cookie的改进,提供了更大的存储容量(在Google Chrome(https://plus.google.com/u/0/+FrancoisBeaufort/posts/S5Q9HqDB8bh)、Mozilla Firefox和Opera中每个来源10MB;在Internet Explorer中每个存储区域10MB)以及更好的编程接口。

还引用了John Resig的一篇文章(发布于2007年1月):

存储空间

DOM 存储提供的存储空间比 Cookie 的典型用户代理限制要大得多,但是规范中并没有定义提供的存储量,并且用户代理也没有明确说明。

如果查看 Mozilla 源代码,可以看到整个域的默认存储大小为 5120KB。这给了你比典型的 2KB cookie 更多的可用空间。

然而,该存储区域的大小可以由用户自定义(因此不能保证有 5MB 存储区域,也不意味着有),并且用户代理(例如 Opera 可能仅提供 3MB - 但只有时间才能告诉我们)。


34
不,这意味着每个“域名”(“起源”)可以在任何单独的客户端上存储5MB。数据存储在客户端机器上 - localStorage机制绝不会在不同客户端之间进行交互。 - DanielB
7
不,我只是想确保同一域名下的多个页面可以访问相同的数据。通常我发现域名和页面这两个词在写作中被用作同义词,所以只是想确认一下! - SexyBeast
11
然而,是否存在对单个值的限制?(如果我有很多标志需要存储,将其存储为JSON格式的单个属性安全吗?) - phtrivier
6
我有5MB的Safari和10MB的Chrome 39(不确定它何时从5MB增加)。参见此文章http://www.html5rocks.com/en/tutorials/offline/quota-research/。 - Ally
37
@Cupidvogel:不是按域名区分,而是按来源区分,这个术语通常与同源策略等相关。具体来说是根据协议+主机名+端口号来区分的。例如,http://example.comhttps://example.com不是同一来源(协议不同),http://example.comhttp://www.example.com也不是同一来源(主机名不同),http://example.comhttp://example.com:8080也不是同一来源(端口号不同)。希望对你有所帮助。 :-) - T.J. Crowder
显示剩余6条评论

164

实际上,Opera浏览器没有5MB的限制。它会根据应用程序需要增加存储量。用户甚至可以选择为域名提供“无限制的存储空间”。

您可以轻松地测试本地存储限制/配额


57
不再崩溃Chrome了... 有趣的一点是:在Chrome上,5MB相当于2.5百万个字符。因此,很明显,localStore使用的是UFT16编码。 - Felix Alcala
1
很遗憾,@FelixAlcala,它会导致Mac OS X上Chrome 15.0.874.54 beta崩溃。我在1,500,000个字符处崩溃了。 - Ivan Vučica
它在我的设备上导致 Chrome 崩溃,同时重置了背景,虽然不意外,因为我的手机内存很小,无法处理在打开 Chrome 的同时打开一个愚蠢的手电筒应用。 - Sophie
6
@FelixAlcala -- 实际上,JavaScript公开了UCS-2。虽然它类似于UTF16,但有一些非常重要的区别……主要围绕着UCS-2比UTF早的事实。 - Jeremy J Starcher
6
最近我在Chrome 80上运行了这个测试,结果是仍允许5MB的情况下,获得了520万个字符。 - Elijah Mock
显示剩余2条评论

107

这是一个简单的脚本,用于查找极限:

if (localStorage && !localStorage.getItem('size')) {
    var i = 0;
    try {
        // Test up to 10 MB
        for (i = 250; i <= 10000; i += 250) {
            localStorage.setItem('test', new Array((i * 1024) + 1).join('a'));
        }
    } catch (e) {
        localStorage.removeItem('test');
        localStorage.setItem('size', i - 250);            
    }
}

这里是代码片段JSFiddle博客文章

脚本将测试设置越来越大的文本字符串,直到浏览器抛出异常。此时,它将清除测试数据并在localStorage中设置一个大小键,以存储以千字节为单位的大小。


1
很棒的解决方案。我发现了这个一行代码,你觉得怎么样? - brasofilo
2
@brasofilo 我认为这个一行代码假设你有5MB,然后减去正在使用的数量。 - cdmckay
好的,一定没问题。我在你的代码中遇到的问题是无法正确地得到在Javascript中将字节大小转换为KB、MB、GB的正确方法的结果...我明天会修改这个问题,但如果你能看一下,我会很感激。 - brasofilo
1
优化了这个答案的性能和质量 这里 - smnbbrv
1
到了2020年,这个答案在Win10上的原版Chrome和Firefox上都可以完美地运行,返回size=5000。 - Alberto Chiesa
不错的解决方案,不过我把循环反转了,因为我认为这样可以减少循环次数,从10000开始递减循环而不是增加数字。当没有错误发生时,你可以使用break。 - Lau

46

查找可以存储在localStorage中的单个字符串的最大长度

此代码段将查找每个域名可在localStorage中存储的字符串的最大长度。

//Clear localStorage
for (var item in localStorage) delete localStorage[item];

window.result = window.result || document.getElementById('result');

result.textContent = 'Test running…';

//Start test
//Defer running so DOM can be updated with "test running" message
setTimeout(function () {

    //Variables
    var low = 0,
        high = 2e9,
        half;

    //Two billion may be a little low as a starting point, so increase if necessary
    while (canStore(high)) high *= 2;


    //Keep refining until low and high are equal
    while (low !== high) {
        half = Math.floor((high - low) / 2 + low);

        //Check if we can't scale down any further
        if (low === half || high === half) {
            console.info(low, high, half);
            //Set low to the maximum possible amount that can be stored 
            low = canStore(high) ? high : low;
            high = low;
            break;
        }


        //Check if the maximum storage is no higher than half
        if (storageMaxBetween(low, half)) {
            high = half;
            //The only other possibility is that it's higher than half but not higher than "high"
        } else {
            low = half + 1;
        }

    }

    //Show the result we found!
    result.innerHTML = 'The maximum length of a string that can be stored in localStorage is <strong>' + low + '</strong> characters.';

    //Functions
    function canStore(strLen) {
        try {
            delete localStorage.foo;
            localStorage.foo = Array(strLen + 1).join('A');
            return true;
        } catch (ex) {
            return false;
        }
    }


    function storageMaxBetween(low, high) {
        return canStore(low) && !canStore(high);
    }

}, 0);

<h1>LocalStorage single value max length test</h1>

<div id='result'>Please enable JavaScript</div>

请注意,JavaScript中的字符串长度是有限制的;如果你想要查看在不限于单个字符串的情况下可以存储的最大数据量,你可以使用这个答案中的代码编辑: Stack Snippets不支持localStorage,因此这里是JSFiddle的链接

结果

Chrome(45.0.2454.101):5242878个字符
Firefox(40.0.1):5242883个字符
Internet Explorer(11.0.9600.18036)16386122066122070个字符
在Internet Explorer中,每次运行的结果都不同。

1
有趣的是,当我在Edge浏览器(Win 10上)运行了约1分钟后,在测试您的简单测试时,我的强大系统崩溃了。因此,我无法将新数据附加到您的结果中)) - vatavale

28

24

我编写了这个简单的代码,用于测试以字节为单位的localStorage大小。

https://github.com/gkucmierz/Test-of-localStorage-limits-quota

const check = bytes => {
  try {
    localStorage.clear();
    localStorage.setItem('a', '0'.repeat(bytes));
    localStorage.clear();
    return true;
  } catch(e) {
    localStorage.clear();
    return false;
  }
};

Github页面:

https://gkucmierz.github.io/Test-of-localStorage-limits-quota/

我在桌面版Google Chrome、Opera、Firefox、Brave和移动版Chrome上获得了相同的结果,大约为10兆字节。

输入图像描述

而在Safari中则达到了一半的大小,约为4兆字节。

输入图像描述


5
使用“UCS-2”编码存储的字符数量约为500万个,相当于10MB,而不是5MB。JavaScript使用类似于“UTF-16”的“UCS-2”编码,每个字符需要2个字节。 - Gael
2
没错,在这里 https://github.com/gkucmierz/Test-of-localStorage-limits-quota/issues/1 指出了这个问题,现在已经修复了。 - gkucmierz

17

不要将大型对象字符串化成单个localStorage条目。这样做非常低效 - 每次发生轻微更改时,整个对象都必须被解析和重新编码。此外,JSON无法处理对象结构内的多个交叉引用,并且会清除很多细节,例如构造函数、数组的非数字属性、稀疏条目中的内容等。

相反,您可以使用Rhaboo。它使用许多localStorage条目存储大型对象,因此您可以快速进行小的更改。恢复的对象是保存对象的非常准确的副本,而且API非常简单。例如:

var store = Rhaboo.persistent('Some name');
store.write('count', store.count ? store.count+1 : 1);
store.write('somethingfancy', {
  one: ['man', 'went'],
  2: 'mow',
  went: [  2, { mow: ['a', 'meadow' ] }, {}  ]
});
store.somethingfancy.went[1].mow.write(1, 'lawn');

顺便说一下,这是我写的。


1
谢谢Martin。你也可以查看我的“evon”存储库。目前它只是一个序列化程序,而且还很新鲜,但它比rhaboo更快,同样灵活。Rhaboo很快将被转换为内部使用它。 - Adrian May
17
有用但我认为这并没有回答“localStorage的最大容量是多少”的问题;你可以通过说明当此库尝试存储超出大小限制的内容时会发生什么,以及如何对此做出反应来改进你的答案。 - Chris Moschini
1
很酷,但不是问题的答案。-1。 - Philippe-André Lorin

9
我将一个二进制测试压缩成了这个函数,我经常使用它:
function getStorageTotalSize(upperLimit/*in bytes*/) {
    var store = localStorage, testkey = "$_test"; // (NOTE: Test key is part of the storage!!! It should also be an even number of characters)
    var test = function (_size) { try { store.removeItem(testkey); store.setItem(testkey, new Array(_size + 1).join('0')); } catch (_ex) { return false; } return true; }
    var backup = {};
    for (var i = 0, n = store.length; i < n; ++i) backup[store.key(i)] = store.getItem(store.key(i));
    store.clear(); // (you could iterate over the items and backup first then restore later)
    var low = 0, high = 1, _upperLimit = (upperLimit || 1024 * 1024 * 1024) / 2, upperTest = true;
    while ((upperTest = test(high)) && high < _upperLimit) { low = high; high *= 2; }
    if (!upperTest) {
        var half = ~~((high - low + 1) / 2); // (~~ is a faster Math.floor())
        high -= half;
        while (half > 0) high += (half = ~~(half / 2)) * (test(high) ? 1 : -1);
        high = testkey.length + high;
    }
    if (high > _upperLimit) high = _upperLimit;
    store.removeItem(testkey);
    for (var p in backup) store.setItem(p, backup[p]);
    return high * 2; // (*2 because of Unicode storage)
}

它在测试之前备份内容,然后恢复它们。

其工作原理是: 在测试失败或达到限制之前,它会将大小加倍。然后存储低和高之间的距离的一半,并每次减去/添加半个距离的一半(失败时减去,成功时添加); 逐渐接近正确的值。

upperLimit 默认为1GB,只是在指数扫描多远之后开始二分查找。我认为这甚至不需要更改,但我总是考虑未来。 ;)

在Chrome上:

> getStorageTotalSize();
> 10485762
> 10485762/2
> 5242881
> localStorage.setItem("a", new Array(5242880).join("0")) // works
> localStorage.setItem("a", new Array(5242881).join("0")) // fails ('a' takes one spot [2 bytes])

IE11、Edge和FireFox也报告相同的最大大小(10485762字节)。


1
在测试前和测试后不要忘记执行 localStorage.Clear() - simonmysun
不需要,这个函数已经清除了项目并在之后恢复它们。 - James Wilkins

7

你可以在现代浏览器中使用以下代码来实时高效地检查存储配额(总数和已用):

if ('storage' in navigator && 'estimate' in navigator.storage) {
        navigator.storage.estimate()
            .then(estimate => {
                console.log("Usage (in Bytes): ", estimate.usage,
                            ",  Total Quota (in Bytes): ", estimate.quota);
            });
}

2
不适用于Chrome浏览器。使用量(以字节为单位):647,总配额(以字节为单位):32901464711。那是错的:实际上可能的总大小是10485762。 - James Wilkins
我的localStorage已经完全满了(无法写入),但估计显示使用情况(以字节为单位):22849625,总配额(以字节为单位):600121223577。 - djdance

7
我正在进行以下操作:
getLocalStorageSizeLimit = function () {

    var maxLength = Math.pow(2,24);
    var preLength = 0;
    var hugeString = "0";
    var testString;
    var keyName = "testingLengthKey";

    //2^24 = 16777216 should be enough to all browsers
    testString = (new Array(Math.pow(2, 24))).join("X");

    while (maxLength !== preLength) {
        try  {
            localStorage.setItem(keyName, testString);

            preLength = testString.length;
            maxLength = Math.ceil(preLength + ((hugeString.length - preLength) / 2));

            testString = hugeString.substr(0, maxLength);
        } catch (e) {
            hugeString = testString;

            maxLength = Math.floor(testString.length - (testString.length - preLength) / 2);
            testString = hugeString.substr(0, maxLength);
        }
    }

    localStorage.removeItem(keyName);

    // Original used this.storageObject in place of localStorage.  I can only guess the goal is to check the size of the localStorage with everything but the testString given that maxLength is then added.
    maxLength = JSON.stringify(localStorage).length + maxLength + keyName.length - 2;

    return maxLength;
};

5
Maroun Maroun:请再次查看帖子,作者提供了代码以编程方式检查本地存储的最大大小。这似乎是一个有效的答案,而不是另一个问题。 - Arend
执行这段代码会在Chrome中抛出一个“非法返回语句”的错误,截至撰写本文时。 - DrewT

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接