使用 localStorage 保存数据

这篇文章由 Jeff Balogh 撰写。Jeff 是 Mozilla 的 网页开发团队 成员。

在 Firefox 3.5 中新增加的 localStorageWeb 存储 规范的一部分。localStorage 提供了一个简单的 Javascript API 用于在浏览器中持久保存键值对。不要将其与 SQL 数据库存储 提议混淆,后者是 Web 存储规范中一个独立的(更具争议性)部分。键值对原则上可以在 cookie 中存储,但你不会想那样做。 cookie 在每次请求时都会发送到服务器,这会导致大型数据集的性能问题以及潜在的安全问题,并且你必须编写自己的接口来将 cookie 当作数据库一样对待。

这里有一个小型演示程序,它将 textarea 的内容存储在 localStorage 中。你可以更改文本,打开一个新标签页,并找到更新后的内容。或者你可以重新启动浏览器,你的文本仍然存在。


使用 localStorage 最简单的方法是将其像普通对象一样对待

>>> localStorage.foo = 'bar'
>>> localStorage.foo
"bar"
>>> localStorage.length
1
>>> localStorage[0]
"foo"
>>> localStorage['foo']
"bar"
>>> delete localStorage['foo']
>>> localStorage.length
0
>>> localStorage.not_set
null

对于喜欢这种方式的人来说,还有一种更冗长的 API

>>> localStorage.clear()
>>> localStorage.setItem('foo', 'bar')
>>> localStorage.getItem('foo')
"bar"
>>> localStorage.key(0)
"foo"
>>> localStorage.removeItem('foo')
>>> localStorage.length
0

如果你想拥有一个映射到当前会话的 localStorage 数据库,可以使用 sessionStorage。它与 localStorage 具有相同的接口,但 sessionStorage 的生命周期仅限于当前浏览器窗口。你可以在同一个窗口中四处跳转链接,sessionStorage 会被保留(转到不同的网站也可以),但是一旦该窗口关闭,数据库就会被删除。localStorage 用于长期存储,正如 w3c 规范中所指示的那样,浏览器应将数据视为“可能对用户至关重要”。

当我发现 localStorage 只能存储字符串时,我有点失望,因为我当时希望它能够存储更结构化的东西。但是借助 原生 JSON 支持,很容易在 localStorage 之上创建一个对象存储。

Storage.prototype.setObject = function(key, value) {
    this.setItem(key, JSON.stringify(value));
}

Storage.prototype.getObject = function(key) {
    return JSON.parse(this.getItem(key));
}

localStorage 数据库的范围限定为一个 HTML5 来源,基本上是三元组 (scheme, host, port)。这意味着数据库在同一个域中的所有页面之间共享,即使在多个浏览器标签页中同时使用也是如此。但是,通过 http:// 连接的页面无法看到在 https:// 会话期间创建的数据库。

localStoragesessionStorage 由 Firefox 3.5、Safari 4.0 和 IE8 支持。你可以在 quirksmode.org 上找到更多兼容性详细信息,包括关于 存储事件 的更多细节。


37 条评论

  1. Mike Beltzner

    嗯。我之前没想过用这种方式来序列化/解析 JSON。而且我敢打赌,有了原生 JSON 支持,这会非常快,对吧?

    很棒的文章。

    2009 年 6 月 25 日 晚上 9:47

    1. Chris McKee

      我最近看到的测试显示,eval 解析 JSON 更快……当代码为全时使用而清理后,这种情况会发生变化

      http://jsperf.com/json-parsing/12

      2010 年 8 月 20 日 下午 4:51

  2. […] 原文地址:saving data with localStorage 系列地址:颠覆网络35天 […]

    2009 年 6 月 25 日 晚上 11:24

  3. Theodora Vorbix

    我一直使用 localStorage 进行黑客攻击,如果它能原生管理集合的话,它完全可以替代 sqlite。

    现在我们可以保存 localStorage.user=”john”

    如果我们也可以保存 localStorage.user[0] = “jane” 就更酷了

    现在我们还不能,但通过简单的黑客操作就可以实现。

    我已经用数百条记录对其进行了测试,效果很好。

    请考虑在 firefox.next 中处理 localStorage 中的集合。

    2009 年 6 月 26 日 上午 11:01

  4. Theodora Vorbix

    这里有一些关于集合的测试

    http://georgenava.googlepages.com/localstorage.html

    2009 年 6 月 26 日 下午 12:23

  5. Al

    再见,cookie!(我不会想念你的。)

    2009 年 6 月 26 日 下午 4:31

  6. Shane

    Al,我认为这并不能替代 cookie。LocalStorage 正如其名,是本地的。我认为它不会返回到服务器,所以你无法将其用于维护登录状态。你仍然需要 cookie 来完成这项工作。(不过,我猜你可以使用 XHR 发送 localStorage 数据,但为什么要这样做呢?当 cookie 能够很好地完成工作并保存相同的数据时?)

    2009 年 6 月 27 日 上午 8:13

  7. bd_

    用户如何清除此数据?据我所知,清除 cookie 或使用“清除最近历史记录”不起作用……

    2009 年 6 月 29 日 上午 6:43

    1. ant

      删除持久存储

      2010 年 12 月 15 日 上午 12:10

  8. foobar

    真是太棒了,我的硬盘里又多了垃圾。cookie 已经够糟糕了。

    2009 年 6 月 29 日 上午 11:56

  9. Tom Chiverton

    “我认为这并不能替代 cookie”
    是的,尤其是因为链接的 QuirksMode 博客文章充满了“浏览器 X 执行 Y,但浏览器 A 执行 B,浏览器 W 只告诉你 K”等等。

    2009 年 6 月 30 日 上午 6:43

  10. Firefox 3.5……

    星期二应该会看到
    Firefox 3.5 的发布,它有很多激动人心的功能,我希望能够从这个博客中利用这些功能——
    包括使用 localStorage 来实现
    “自动保存”功能,这应该可以减少很多不必要的……

    2009 年 6 月 30 日 上午 7:37

  11. […] 它由 Mozilla 网页开发团队的 Jeff Balogh 撰写 链接:https://hacks.mozilla.ac.cn/2009/06/localstorage/ […]

    2009 年 7 月 2 日 上午 4:07

  12. lunter

    IE8:Storage.prototype 不起作用

    Storage.prototype.setObject = function(key, value) {
    this.setItem(key, JSON.stringify(value));
    }

    Storage.prototype.getObject = function(key) {
    return JSON.parse(this.getItem(key));
    }

    2009 年 8 月 3 日 上午 2:40

  13. lrbabe

    通过结合使用 canvas 的 drawImage 和 toDataUrl,甚至可以在 localStorage 中存储图像。
    但是,任何 localStorage 都有一定的尺寸限制。

    2009 年 8 月 8 日 下午 4:44

  14. […] 原文地址:saving data with localStorage 系列地址:颠覆网络35天 […]

    2009 年 8 月 13 日 晚上 9:32

  15. […] 还为支持 localStorage 的浏览器用户(包括 Firefox 3.5)添加了一款福利:最近查看的集合。当浏览集合时……

    2009 年 8 月 28 日 上午 12:28

  16. […] 还为支持 localStorage 的浏览器用户(包括 Firefox 3.5)添加了一款福利:最近查看的集合。当浏览集合时……

    2009 年 8 月 28 日 上午 9:53

  17. […] 感谢 Twitter 在 JSON 响应中提供了方便的“回调”参数。我使用了一些现代浏览器支持的 localStorage 属性来记住用户的关注者历史记录。……

    2009 年 9 月 18 日 晚上 8:42

  18. […] 正在探索使用 FireFox 的 LocalStorage、HTML5 的本地数据库和 Chrome 的 Google Gears 实现离线客户端存储的最佳方法。PersistJS 等项目已经尝试过……

    2009 年 10 月 21 日 晚上 8:46

  19. […] 正在探索使用 FireFox 的 LocalStorage、HTML5 的本地数据库和 Chrome 的 Google Gears 实现离线客户端存储的最佳方法。PersistJS 等项目已经尝试过……

    2009 年 12 月 6 日 上午 10:42

  20. Amos

    根据 HTML5 规范,存储对象应该支持持久保存任何 javascript 对象,而不仅仅是 String 类型。但是,FF3.5 的实现似乎并非如此(因此文章中使用了 JSON 黑客操作)。
    为什么只部分实现了这个功能?

    2010 年 2 月 10 日 上午 6:42

  21. james

    简单易懂的功能——解释得很好——我正在尝试将其与一些图形链接在一起,其中 filament group 在 canvas 上做了一些不错的作品,然后找到一种将本地存储与基于服务器的数据同步的方法——应该很简单,而且非常适合控制用户的存储限制

    2010 年 2 月 18 日 下午 1:00

  22. Sid Maestre

    谢谢!我正在开发一个 HTML/CSS/JQuery iPhone 应用,并希望将对象保存到 localStorage 中。你关于保存 JSON 对象的建议非常有效。

    2010 年 3 月 17 日 下午 07:58

  23. HM

    这是否只适用于托管网站?即使刷新页面(按 F5),我仍然无法让它记住。

    文件是
    file:///home/me/workspace/course/test.htm

    文件的内容是
    hi

    document.getElementById(“out”).value = localStorage.lesson;
    function setStorage(){
    localStorage.lesson=document.getElementById(“in”).value;
    document.getElementById(“out”).value = localStorage.lesson;
    }

    我按下按钮,另一个文本区域被设置,按 F5 后 localStorage.lesson 为 null。

    这是在 Linux Mint 3.5.9 上。

    2010 年 5 月 15 日 上午 03:33

  24. Daniel O’Connor

    令人讨厌的是,如果 localStorage 中没有为给定键填充数据,Chrome 会抛出“未捕获的非法访问”异常。

    更好的方法可能是:

    /**
    * Firefox 解决方案 - 将对象序列化为 JSON
    *
    * @see https://hacks.mozilla.ac.cn/2009/06/localstorage/
    */
    Storage.prototype.setObject = function(key, value) {
    this.setItem(key, JSON.stringify(value));
    };

    /**
    * Firefox 解决方案 - 从 JSON 反序列化对象
    *
    * @see https://hacks.mozilla.ac.cn/2009/06/localstorage/
    */
    Storage.prototype.getObject = function(key) {
    try {
    return JSON.parse(this.getItem(key));
    } catch (e) {
    return null;
    }
    };

    2010 年 6 月 3 日 下午 20:04

  25. [...] HTML5 localStorage: 即使浏览器重启,也能保存图像数据。[...]

    2010 年 7 月 7 日 上午 09:04

  26. sofish

    我在第一个 <textarea> 中输入了“hmmm...” ,然后复制了此页面的 URL,并在新标签页中打开... 在那里,第一个 <textare> 给出了“答案”:未定义。在 Fx 3.6.6 中测试。

    2010 年 7 月 12 日 下午 19:06

  27. Oscar Godson

    只是个问题,为什么当 URL 协议为 file:// 时,我们不能在本地使用它?我花了大约一个小时排查问题,但真的没有理由。

    2010 年 7 月 21 日 下午 15:40

  28. David Laurell

    @Oscar Godson
    也许是因为 localStorage 仅限于域,而当你本地查看页面时,你没有域?

    你现在可能已经弄明白了,但其他人可能想知道答案。

    2010 年 10 月 8 日 上午 07:59

  29. Mozilla 黑客

    要在 Windows 上删除 localStorage,请关闭 Firefox,然后导航到 %USERPROFILE%Application DataMozillaFirefoxProfiles[一些随机字符串].default。在该目录中,删除 sessionstore.*。

    对于其他操作系统,在上面的演示窗口中输入一个唯一的字符串,然后在 shell 中使用“grep -rli .” 查找 sessionstore.js 的位置。该文件显然是实时填充的。

    我刚刚发现了 localStorage,它已经充满了大量不需要的跟踪数据。

    2010 年 10 月 9 日 下午 20:46

    1. Mozilla 黑客

      我必须修改我之前的帖子:你必须同时删除 webappstore.sqlite,否则 sessionstore.js 会从它中恢复。

      2010 年 10 月 9 日 下午 20:52

  30. phil

    大家好,

    在你用 localStorage 替换 cookies(如果有些人使用这个坏东西)之前,你必须知道你可能会在托管网站上遇到麻烦和黑客问题。

    当你写入 cookie 时,你可以设置 PATH,以便其他用户的页面无法读取它。
    由于 localStorage 是按站点(域)来区分的,因此同一托管服务器上的其他用户的页面将能够读取甚至更新你 localStorage 中的条目。

    所以 localStorage 很好,但你必须巧妙地使用它;o)

    2010 年 11 月 9 日 下午 12:17

    1. Steve

      嗨,Phil,

      你是否将 $_SESSION 和 $_COOKIE 服务器端变量与 localStorage 混淆了,localStorage 严格来说是客户端专属的。

      2010 年 12 月 12 日 下午 18:27

  31. [...] https://hacks.mozilla.ac.cn/2009/06/localstorage/ [...]

    2011 年 6 月 2 日 上午 00:36

  32. [...] 世界上最广泛的游戏地图,不会减慢用户主页界面的速度;localStorage,它不断保存角色的进度和 HTML5 [...]

    2012 年 4 月 12 日 下午 15:26

  33. Noe Dadon

    用法示例

    window.localStorage.setObject(‘obj’,{name:’math’,description:’mathDescription’})

    window.localStorage.getObject(‘obj’);

    2013 年 2 月 5 日 上午 02:32

本文的评论已关闭。