在 localStorage 中保存图片和文件

如您所知,localStorage 在将信息快速存储在用户的 Web 浏览器中方面非常强大,并且在所有 Web 浏览器中也存在了很长时间。但是,我们如何在其中存储文件呢?

请务必阅读 在 IndexedDB 中存储图片和文件.

使用 JSON 实现强大的控制

让我们从关于 localStorage 的一些基本信息开始。在 localStorage 中存储信息时,您使用键值对,如下所示

localStorage.setItem("name", "Robert");

要读取它,您只需获取该键的值

localStorage.getItem("name");

这很好,并且能够保存至少 5 MB,您有很多选择。但是,由于 localStorage 只是基于字符串的,因此保存一个没有结构形式的长字符串并不是最佳选择。
因此,我们可以利用 Web 浏览器中的原生 JSON 支持将 JavaScript 对象转换为字符串以进行保存,并在读取时将其转换回对象


var cast = {
    "Adm. Adama" : "Edward James Olmos",
    "President Roslin" : "Mary McDonnell",
    "Captain Adama" : "Jamie Bamber",
    "Gaius Baltar" : "James Callis",
    "Number Six" : "Tricia Helfer",
    "Kara Thrace" : "	Katee Sackhoff"
};

// Stores the JavaScript object as a string
localStorage.setItem("cast", JSON.stringify(cast));

// Parses the saved string into a JavaScript object again
JSON.parse(localStorage.getItem("cast"));

存储图片

这里的想法是能够获取已加载到当前网页中的图片并将其存储到 localStorage 中。正如我们在上面所述,localStorage 仅支持字符串,因此我们需要做的是将图片转换为 Data URL。对图片执行此操作的一种方法是将其加载到 canvas 元素 中。然后,使用 canvas,您可以将当前的视觉表示形式从 canvas 读取为 Data URL。

让我们看一下这个示例,其中我们在文档中有一个 id 为“elephant”的图片


// Get a reference to the image element
var elephant = document.getElementById("elephant");

// Take action when the image has loaded
elephant.addEventListener("load", function () {
    var imgCanvas = document.createElement("canvas"),
        imgContext = imgCanvas.getContext("2d");

    // Make sure canvas is as big as the picture
    imgCanvas.width = elephant.width;
    imgCanvas.height = elephant.height;

    // Draw image into canvas element
    imgContext.drawImage(elephant, 0, 0, elephant.width, elephant.height);

    // Get canvas contents as a data URL
    var imgAsDataURL = imgCanvas.toDataURL("image/png");

    // Save image into localStorage
    localStorage.setItem("elephant", imgAsDataURL);
}, false);

然后,如果我们想更进一步,我们可以利用一个 JavaScript 对象,并对 localStorage 进行日期检查。在这个例子中,我们第一次通过 JavaScript 从服务器加载图片,但是对于之后每次页面加载,我们都会从 localStorage 读取保存的图片

HTML


<figure>
    <img id="elephant" src="about:blank" alt="A close up of an elephant">
    <noscript>
        <img src="elephant.png" alt="A close up of an elephant">
    </noscript>
    <figcaption>A mighty big elephant, and mighty close too!</figcaption>
</figure>

JavaScript


// localStorage with image
var storageFiles = JSON.parse(localStorage.getItem("storageFiles")) || {},
    elephant = document.getElementById("elephant"),
    storageFilesDate = storageFiles.date,
    date = new Date(),
    todaysDate = (date.getMonth() + 1).toString() + date.getDate().toString();

// Compare date and create localStorage if it's not existing/too old
if (typeof storageFilesDate === "undefined" || storageFilesDate < todaysDate) {
    // Take action when the image has loaded
    elephant.addEventListener("load", function () {
        var imgCanvas = document.createElement("canvas"),
            imgContext = imgCanvas.getContext("2d");

        // Make sure canvas is as big as the picture
        imgCanvas.width = elephant.width;
        imgCanvas.height = elephant.height;

        // Draw image into canvas element
        imgContext.drawImage(elephant, 0, 0, elephant.width, elephant.height);

        // Save image as a data URL
        storageFiles.elephant = imgCanvas.toDataURL("image/png");

        // Set date for localStorage
        storageFiles.date = todaysDate;

        // Save as JSON in localStorage
        localStorage.setItem("storageFiles", JSON.stringify(storageFiles));
    }, false);

    // Set initial image src
    elephant.setAttribute("src", "elephant.png");
}
else {
    // Use image from localStorage
    elephant.setAttribute("src", storageFiles.elephant);
}

注意:这里需要注意的是,您可能会超过 localStorage 中可用的大小,最好的控制方法是使用 try...catch

存储任何类型的文件

太好了,我们可以使用 canvas 将图片转换为 Data URL 并保存到 localStorage 中。但是,如果我们想要一个适用于任何类型文件的机制呢?

然后它就会变得有点意思,我们需要使用

基本方法是

  1. 对文件执行 XMLHttpRequest,并将 responseType 设置为“arraybuffer”
  2. 将 XMLHttpRequest 的响应(即文件)加载到 Blob 中
  3. 使用 FileReader 读取该文件并将其加载到页面和/或 localStorage 中

让我们来看一个完整的示例,其中我们请求一个名为“rhino.png”的图片,将其保存到 blob 中,使用 FileReader 读取文件,最后将其保存到 localStorage 中


// Getting a file through XMLHttpRequest as an arraybuffer and creating a Blob
var rhinoStorage = localStorage.getItem("rhino"),
    rhino = document.getElementById("rhino");
if (rhinoStorage) {
    // Reuse existing Data URL from localStorage
    rhino.setAttribute("src", rhinoStorage);
}
else {
    // Create XHR, Blob and FileReader objects
    var xhr = new XMLHttpRequest(),
        blob,
        fileReader = new FileReader();

    xhr.open("GET", "rhino.png", true);
    // Set the responseType to arraybuffer. "blob" is an option too, rendering manual Blob creation unnecessary, but the support for "blob" is not widespread enough yet
    xhr.responseType = "arraybuffer";

    xhr.addEventListener("load", function () {
        if (xhr.status === 200) {
            // Create a blob from the response
            blob = new Blob([xhr.response], {type: "image/png"});

            // onload needed since Google Chrome doesn't support addEventListener for FileReader
            fileReader.onload = function (evt) {
                // Read out file contents as a Data URL
                var result = evt.target.result;
                // Set image src to Data URL
                rhino.setAttribute("src", result);
                // Store Data URL in localStorage
                localStorage.setItem("rhino", result);
            };
            // Load blob as Data URL
            fileReader.readAsDataURL(blob);
        }
    }, false);
    // Send XHR
    xhr.send();
}

使用“blob”作为 responseType

在上面的示例中,我们使用了 responseType“arraybuffer”和一个 Blob 来创建我们可以用于 FileReader 的东西。但是,还有一个名为“blob”的 responseType,它直接返回一个 blob,我们可以将其与 FileReader 一起使用。然后,上面的示例将如下所示


// Getting a file through XMLHttpRequest as an arraybuffer and creating a Blob
var rhinoStorage = localStorage.getItem("rhino"),
    rhino = document.getElementById("rhino");
if (rhinoStorage) {
    // Reuse existing Data URL from localStorage
    rhino.setAttribute("src", rhinoStorage);
}
else {
    // Create XHR and FileReader objects
    var xhr = new XMLHttpRequest(),
        fileReader = new FileReader();

    xhr.open("GET", "rhino.png", true);
    // Set the responseType to blob
    xhr.responseType = "blob";

    xhr.addEventListener("load", function () {
        if (xhr.status === 200) {
            // onload needed since Google Chrome doesn't support addEventListener for FileReader
            fileReader.onload = function (evt) {
                // Read out file contents as a Data URL
                var result = evt.target.result;
                // Set image src to Data URL
                rhino.setAttribute("src", result);
                // Store Data URL in localStorage
                localStorage.setItem("rhino", result);
            };
            // Load blob as Data URL
            fileReader.readAsDataURL(xhr.response);
        }
    }, false);
    // Send XHR
    xhr.send();
}

Web 浏览器支持

localStorage
在所有主要的 Web 浏览器中都已支持很长时间,包括 IE8。
原生 JSON 支持
与 localStorage 相同的长期支持。
canvas 元素
在大多数主要的 Web 浏览器中都已支持很长时间,但仅从 IE9 开始支持。
XMLHttpRequest 2 级
在 Firefox 和 Google Chrome 中已支持很长时间,在 Safari 5+ 中支持,并计划在 IE10 和 Opera 12 中支持。
Blob
在 Firefox 和 Google Chrome 中已支持很长时间,并计划在 IE10 中支持。也支持 Safari 6.0+ 和 Opera Opera 12.1+
FileReader
在 Firefox 和 Google Chrome 中已支持很长时间,Opera 11.1 开始支持,并计划在 IE10 中支持。Safari 尚不清楚。
responseType“blob”
目前仅在 Firefox 中支持。很快将在 Google Chrome 中支持,并计划在 IE10 中支持。Safari 和 Opera 尚不清楚。

检查和清除 localStorage

检查 localStorage 中内容的最简单方法

  • Firebug:DOM 选项卡,然后向下滚动到或搜索 localStorage
  • Google Chrome:开发者工具,在“资源”选项卡下
  • Opera:在 Opera Dragonfly 的“存储”选项卡中

演示和代码

我创建了一个 使用 localStorage 保存图片和文件的演示,您可以在其中看到 canvas 方法和使用 XMLHtpRequest 2、Blob 和 FileReader 的方法。

用于 在 localStorage 中存储文件 的代码也可以在 GitHub 上找到,现在就去体验一下吧!

关于 Robert Nyman [资深编辑]

Mozilla Hacks 的技术布道师和编辑。发表关于 HTML5、JavaScript 和开放网络的演讲和博客文章。Robert 是 HTML5 和开放网络的坚定支持者,自 1999 年以来一直在从事网页前端开发工作 - 在瑞典和纽约市。他也定期在 http://robertnyman.com 上发博,喜欢旅行和结识新朋友。

更多 Robert Nyman [资深编辑] 的文章……


46 条评论

  1. Andrea Gimmarchi

    对不起,伙计们,但我认为这篇文章具有误导性。
    我们甚至无法控制 localStorage 的大小,而你们却建议将文件存储在一个平均每个选项卡限制为 5 MB 的对象中。
    此外,您只是简单地调用 LS.setItem(“key”, value),而没有在周围使用 try catch,这是迄今为止避免“空间不足”问题并保持应用程序/数据/行为安全一致或受控制的唯一方法。
    此外,localStorage 是同步的,并且不是用作大型数据块和任何文件的 base64(asDataURL)版本的垃圾桶的理想对象,因为我们仍然没有通过 JavaScript 公开原生 gzip 压缩,其大小平均比原始格式大 30%。
    IndexedDB 或 WebSQL 是这类任务的更好解决方案,并且上面这篇文章中缺少所有这些词语:大小、限制、性能、*数据库*。
    不推荐,尽管显示的代码和背后的抽象概念具有良好的质量,但不幸的是,我认为使用的是最糟糕的存储选项。

    2012 年 2 月 21 日 凌晨 3:30

    1. Chris Heilmann

      其中有一些真实的观点(特别是包装在 try…catch 中),但将 IndexDB 作为始终是更好选择的说法是不正确的。例如,我发现很多应用程序在 localStorage 中存储数据,而不是在 indexDB 中存储数据,因为访问速度要快得多(尽管是同步的)。因此,在应用程序启动时,如果您将图片存储在 localStorage 中,速度会更快。base64 编码大小问题是一个老问题。有趣的是,localStorage 采用 UTF-16 字符,因此您可以通过位移将存储空间增加一倍。我现在正在采访《金融时报》应用程序的开发者,他们确实做了一些非常聪明的事情。

      用其他笼统的陈述来谴责笼统的陈述并不能真正帮助解决问题 - Web 开发始终是一种折衷,在没有设置数据库并经历跨浏览器支持问题的情况下,localStorage 有着很棒的用途。

      2012 年 2 月 21 日 凌晨 3:44

    2. Robert Nyman

      感谢您的评论,Andrea。

      您关于 try…catch 的说法绝对正确,我已经更新了博文、代码和演示以反映这一点。对于大小等因素,它始终需要考虑在内。

      WebSQL 不是一种选择,因为它已被弃用,并且永远不会在所有浏览器中实现。IndexedDB 绝对是一种有趣的方法,尽管它还没有完全成熟,因为不同 Web 浏览器实现之间的语法差异很大,而且目前还不支持。

      这并不意味着它是所有文件的最终存储解决方案,而是一种具有简单语法和控制的选项,适用于某些用例。并且它是一种目前更广泛可用的解决方案。

      2012 年 2 月 21 日 凌晨 3:47

      1. Taras Glek

        您想应用什么样的逻辑?我查看了我的 localStorage,发现里面有很多网站,我再也不会访问了(因为没有过期策略)。

        2012 年 3 月 2 日 下午 11:59

        1. Robert Nyman

          任何我能想到的逻辑,对我或其他人来说都是这样。

          过期策略总体上会成为一个问题 - 我同意。在涉及任何类型的存储(离线、localStorage、IndexedDB)时,可能最好让最终用户能够更容易地检查/删除它,这一点适用于所有 Web 浏览器。

          2012 年 3 月 2 日 下午 4:10

    3. Taras Glek

      Andrea,您说得完全正确。DOM 存储 < indexdb。使用它不利于用户响应速度。因此,任何使用它的 Web 应用程序都会在访问它时导致网页冻结。

      2012 年 2 月 21 日 下午 3:25

  2. sonny

    请注意,WebSQL 和 IndexedDB 允许存储 Blob,因此您无需使用高 CPU 成本的 base64 编码/解码操作(参见 window.URL.createObjectURL)。

    2012 年 2 月 21 日 上午 4:36

    1. Robert Nyman

      数据库允许使用 Blob 很棒。不过,我不确定 window.URL.createObjectURL 的提法?

      这可以正常工作,但仅限于创建它的当前文档的生命周期内。

      2012 年 2 月 21 日 上午 6:35

      1. sonny

        是的,我说的是 createObjectURL,这样您就可以使用数据而无需处理 base64 数据,而不是作为存储方法。

        2012 年 2 月 21 日 上午 7:49

        1. Robert Nyman

          啊,没错。是的,它在当前文档中有效,但不能用于将其存储在 localStorage 中。因为如果您利用它,然后用户在另一个选项卡中打开同一页面,例如,ObjectURL 将不起作用。

          2012 年 2 月 21 日 上午 7:51

  3. Ivan

    “typeof” 返回的值始终是字符串。为什么您使用 === 而不是 ==,为什么?

    2012 年 2 月 21 日 上午 5:28

    1. Robert Nyman

      实际上,这是一种习惯。一直以来,这是良好的编码习惯,为了避免任何类型的强制转换,对类型和值进行三重检查。

      2012 年 2 月 21 日 上午 6:11

  4. Andrea Gimmarchi

    Chris … 关于“IndexDB 总是更好的选择,这种说法并不正确”这句话,的确我从未说过,将来也不会说。

    我说的是,对于文件,平均而言,对于一致数量的数据,我*个人*绝不会建议使用 localStorage,因为 a) 它真的有限制,在 5Mb 中,如果您想保留高分辨率等示例,则只有几张高质量的 JPEG 可以通过输入字段保存,而其他内容则无法保存;b) 它同步,因此您以更快的(???)方式访问同步数据以生成某种异步数据,无论如何,每张图像都是异步的,无论使用数据 URL 如何。

    我认为 localStorage 的作用不在于“文件存储”,正如我所说,它背后的理念很好,因为在任何情况下它都与所有其他存储方式有效。

    WebSQL 存在于除 FF 和 IE 之外的所有地方,我怀疑它很快就会消失,但性能很出色(我提醒您,我们在那里存储地图瓦片,在性能方面,特别是手机上,效果惊人),但我建议使用 IndexedDB,它没有 localStorage 的限制,而且更适合使用多个库的页面,并希望存储一些更繁重的数据。

    Sonny,不幸的是,WebSQL 不支持 BLOB(而 SQLite 支持,哎!),或者如果支持,我敢肯定它不是跨平台的。

    总而言之,我的评论并不是针对 Chris 的个人攻击,而是一个“警告”,提示本文中未提及的事项,既然你们 Mozilla 团队比任何人都更关心知识的传播,所以我绝对更欣赏 Robert 的回复,也感谢 Robert 提供的更新。

    保重

    2012 年 2 月 21 日 上午 5:34

    1. Chris Heilmann

      很棒的内容,我感谢您的回复以及对问题的解释。这让我与 Robert 进行了交谈,并对文章进行了些许修改。令人遗憾的是,我们在本地数据库中也遇到了类似于视频的困境(不同的浏览器厂商支持不同的格式)。因此,我认为对于生产环境,我会使用一个抽象层,以浏览器支持的格式存储您的文件。最终,这是我们大多数时候都需要做的事情。

      我从未将此视为个人攻击,我只是发现很多人很快就会使用本地数据库的强大功能,而 localStorage 对于文件来说确实有其正当的用途。这并非意味着“localStorage 适合所有情况”。也许做一个比较图表和决策树供开发者使用会很有趣。您愿意吗?

      2012 年 2 月 21 日 上午 5:54

    2. Robert Nyman

      谢谢!

      我相信这完全取决于用例。数据库很好,但有时会过于复杂。此外,对于 localStorage,它确实有限制,但它也允许您在没有明确用户许可的情况下将内容存储在其中。对于 IndexedDB 和离线/appcache,用户需要额外的步骤。

      所以,这只是您工具集中的一种选择。:-)

      2012 年 2 月 21 日 上午 6:15

    3. sonny

      “Sonny,不幸的是,WebSQL 不支持 BLOB(而 SQLite 支持,哎!),或者如果支持,我敢肯定它不是跨平台的。”
      我知道 Safari 移动版支持它。

      2012 年 2 月 21 日 上午 7:56

      1. Robert Nyman

        我认为,谈到选择,目标是让它尽可能多地可用。WebSQL 永远不会在 Internet Explorer 或 Firefox 中实现,而 localStorage、IndexedDB 和各种文件 API 将存在于所有 Web 浏览器中。

        2012 年 2 月 21 日 上午 8:03

  5. Andrea Giammarchi

    如果我们谈论抽象,那么是的,localStorage 应该是我的首选,作为后备方案,而不是像 Flash SharedObject 那样,对于文件也是如此。当然,在这种情况下,像这样的文章确实非常受欢迎。

    我想,IndexedDB、WebSQL 和 localStorage 差别太大了,无法在一张图表中总结所有优缺点,这样对其中一个或另一个选择会不公平,但如果您有时间整理这张图表,我很乐意对此发表评论。:-)

    再次感谢更新,并致以最诚挚的祝福

    2012 年 2 月 21 日 上午 6:11

    1. Robert Nyman

      感谢您的意见!

      2012 年 2 月 21 日 上午 6:16

  6. Andrea Giammarchi

    没错,localStorage 的行为统一,不需要任何操作。

    关于明确的用户许可,通过 WebSQL,我们发现在 iOS 上,如果初始大小小于或等于 5Mb,则不需要任何操作,对于 10、25 和最终 50 的增量请求,或者当您直接请求限制时,一次性请求,iOS 设备上的限制是 50Mb。

    在 Android 上,似乎根本没有请求,但大小无法预先知道,因此 2.2 到 10Mb,2.3+ 没有任何问题,最多可以达到 45Mb,但 50Mb 会遇到一些问题,而且永远不需要明确的操作。

    最后,我迫不及待地想要 IndexedDB 普及,这样我们就可以采用它,但我希望“请求空间”机制不会太无聊(在我们的案例中,很容易填满 50Mb,例如,5 次明确的操作来占用少量额外的空间,对我们来说简直令人厌烦)。
    请求空间是可以的,让开发人员决定要多少空间,而不限制磁盘或 SD 卡的访问权限,因为没有本地包装器/应用程序有这样的限制,这将使 WebApp 概念更加具体。

    抱歉,这有点跑题,但希望对那些看到这些评论的人有所帮助。

    很快再见,各位

    2012 年 2 月 21 日 上午 7:37

    1. Robert Nyman

      是的,请求空间似乎有所依赖。在桌面 Web 浏览器中,通常差别不大,但在移动设备上差别很大。

      这绝对是一个有趣的挑战!

      2012 年 2 月 21 日 上午 7:49

  7. pd

    ExecSum:插件固然邪恶,但 Flash 多久以前就有了本地存储?而 Web 仍然没有达到相同的普及程度和实用性?

    感谢您探索这个选项,Robert。我认为,每个 Web 开发人员都梦想着能够在客户端存储长期存在的文件。不仅如此,互联网上的每个人,从用户到运营商,都应该将这种节约带宽、提高速度的概念作为目标。

    不幸的是,这篇文章主要是一个很好的例子,说明 Web 作为平台仍然处于什么阶段:不够完善。HTML5 宣讲者请注意!虽然 localStorage 功能的孕育期对于 Web 来说是一个奇怪的时期,因为它从一个死气沉沉的垄断平台演变成今天所谓的“现代”平台,但 localStorage 仍然是 Web 平台功能演变的一个很好的案例研究,因为它是最新的例子之一,说明了同一个老故事:过时、有限且无效的 API。但是,这可能是一个以后再讨论的话题,也可能不会(这篇文章的作者似乎不喜欢对单个博客文章主题如何与大局相关进行宏观分析)。

    以下是我在将 localStorage 作为客户端文件缓存的增强或替代方案时发现的几个问题

    1) 用户权限。
    虽然让开发者能够在客户端存储任何字符串,自然需要用户权限,因为这可能涉及隐私和安全问题,但为什么提示用户(使用他们可能不理解的消息)许可存储缓存中已存储的图像和其他内容,而无需获得权限?我认为最终用户对这种提示的接受程度有限,因此开发者对这种提示的接受程度也有限,因为开发者很少有时间或精力去实施无法保证被广泛采用的解决方案。

    相关但需要注意的一点是,Firefox 的本地存储提示似乎没有帮助部分,而 Flash 则有此部分

    http://www.macromedia.com/support/documentation/en/flashplayer/help/help06.html

    2) 开销。似乎需要大量工作。不要把我贴上懒惰的标签。我只是想知道,组织回退案例需要多少*额外*工作;随着时间的推移维护存储空间(在需要时更新内容,确保不超过 5Mb 限制);衡量随着时间的推移对性能的影响(统计数据)等等。它确实需要像 jQuery 这样的库来采用它并简化它。

    再次感谢您对此的关注。除了奇怪的“since long”短语外,这篇文章很好地概述了 Web 发展超越笨拙的缓存的现状。不幸的是,在我看来,目前的演变状态仍然不是一个非常可行的解决方案,但至少有一点希望。在此期间……我在澳大利亚工作,微软应该已经强制升级了每个人至少到 IE8。但统计数据仍然显示,访问我雇主主要网站的 11% 的访问者仍在使用 IE7。将这种限制与您“Web 浏览器支持”部分中概述的限制结合起来,就是一个很好的例子,说明了 Web 平台在“现代”HTML5 时代之前的以及我猜想在“现代”HTML5 时代期间,未能及时提供有意义的 API。我希望那些实施 HTML5 的人能从这个最新的例子中吸取教训。

    2012 年 2 月 21 日 下午 08:56

    1. Robert Nyman

      谢谢,很高兴你喜欢这篇文章!

      我认为,对我来说,可以很简单地总结一下:Flash 运行时是一种在某些平台上运行的封闭技术,而 HTML5 则是在开放环境中开发的,可以在“所有”平台和 Web 浏览器上运行,无需任何插件。

      对我来说,这是一个巨大的优势。

      > 撰写这篇博文的人似乎不喜欢对单个博文主题如何与大局相关进行宏观层面的分析

      看到这句话我有点难过。你有一个建设性的评论,讨论了重要的事情。请不要浪费它去发表这种言论。

      说到你的观点

      1. 与 IndexedDB 和脱机/应用程序缓存相比,Web 浏览器中没有 localStorage 的提示(根据实现,您的里程可能会有所不同)。

      2. 开销当然是一个相对的术语,是否使用它取决于每个人,以及他们是否认为合适。如果只是简单的缓存,也许使用过期头和常规 Web 浏览器缓存会更好。但如果你想根据某种需求来定制和调整一些东西,这可能是一个选择。

      我还要说,IE7 仍然存在以及直到 IE9 才在 Internet Explorer 中实现 canvas 并不是 HTML5 的错。IE 团队现在正在提供大量的改进,各种标准在各方面越来越得到实施。

      2012 年 2 月 21 日 下午 09:14

  8. pd

    > 撰写这篇博文的人似乎不喜欢对单个博文主题如何与大局相关进行宏观层面的分析

    >> 我看到这句话我有点难过。你有一个建设性的评论,讨论了重要的事情。请不要浪费它去发表这种言论。

    对不起让你难过了,但更让我难过的是,你无法容忍在我其他观点中夹杂的一句相对平衡的、略带批评性的句子。Web 从什么时候变成了一个审查制度的媒介?这句话的核心是,需要比当前这个网站提供的更好的东西,来讨论那些可能与一篇博文相关,但也触及更宏大、更广泛议题的主题。这篇博文的作者选择了博文格式以及它所包含的一切,包括将评论限制在他们出现的单个博文主题中。这篇博文的作者或 Mozilla 的其他部门可以很容易地选择使用论坛格式来呈现此内容,并且这种格式将更有可能对更广泛的讨论主题开放。这正是我想要指出的主要内容。我真后悔在博文中写了这么多内容。我为什么要这么做?如果有 Mozilla 为 Web 开发人员运营的开发者论坛,我就不用这么做了。是的,有 Google Groups,但谁想冒着在那里被火焰化的风险呢?我想说的是,一个论坛可能更受欢迎。

    关于 Flash,我认为你错过了我想表达的重点:这不是政治问题,而是实际问题。我知道 Mozilla 往往将政治放在实际问题之前,我理解这种方法的价值所在,因为它有助于推动开放 Web 的议程。但是,推动开放 Web 议程的方法不止一种。更快速地创建对封闭功能的开放替代方案,有望防止我们再次看到像 Flash 这样占据主导地位的封闭源插件。重点是速度。开发人员现在就需要这些功能,实际上是昨天就需要了,他们永远都需要。并非所有开发人员都能接受并非完全实际的立场,即仅仅因为一个封闭源运行时是封闭的,就忽略通过它提供的功能。“向客户和经理推销”这种政治立场非常困难。而如果开发人员在开放和封闭之间有明确的选择,并且两种解决方案之间的差异很小或没有差异,我相信大多数人会始终选择开放(浏览器而不是插件)选项。这就是近年来浏览器领域新 API 激增的原因。当然,在将大量新 API 推入 Firefox 4 之后,Firefox 再次变得可用花费了两年时间,但如果可以避免这种情况,如果目标是在通过阻击来消除封闭源选项的威胁,那么尽快推出新功能绝对是更好的选择。这就是我喜欢 HTML5 的原因。我还讨厌它缺乏基本的表单小部件,但至少我还是有点喜欢它 :)

    关于第一点,我想有这么多的存储选项争夺关注,所以很容易将 IndexedDB 权限提示误认为是 localStorage 的提示。无论如何,我认为我关于需要从该提示中访问帮助内容的观点仍然是相关的。有一个门牌和一个下拉提示,但它们都没有链接到任何解释用户被要求做什么的帮助内容。门牌上有一个很大的蓝色圆形问号图标,但除此之外什么都没有。

    关于第二点,如果不是因为 HTML4 和 HTML5 之间巨大的延迟,而这种延迟突出了创建 WHATWG 和舍弃 XHTML 的必要性,那么 IE7 是否会拥有更多下一代基于标准的 API 功能,因此 IE8 也会拥有更多?我认为他们可能会,因此 IE7 仍然存在的影响就不那么大了。即使是微软,尽管开发了 SilverLight,但似乎也支持相当合理的开放标准子集,前提是这些标准实际上已经达成一致并准备实施。对微软因创新采用专有或超前于时代的、尚未标准化的功能而进行的批评是巨大的。我现在笑眯眯地坐在后面,看着 Mozilla、Google 和 Apple 都在做同样的事情,也许程度不同。

    我完全清楚,微软停止了他们浏览器的开发,并且他们在克服为其垄断产生的专有标准编写的应用程序的兼容性问题方面遇到了困难。毫无疑问,这阻碍了 IE7 的标准支持。另一方面,如果 2006 年 1 月 31 日发布的公开预览版是可信的,那么 IE7 是在 2005 年开发的。HTML5 甚至在 2007 年之前都没有被 W3C HTML 工作组采用。除非维基百科在撒谎 :) Web 应用程序 1 和 Web 表单 2 当时可能正在酝酿中,但考虑到当时标准化政治的状态,是否公平地期望微软在 IE7 中实施任何现代 API?网络上的表单至今尚未得到大幅改进,臭名昭著的 HTML5 完工日期至今仍然是十年后!

    IE7 仍然存在可能不是 HTML5 的错,但由于其有限的 HTML5 支持,IE7 成为一个红鲱鱼,这也不一定是 IE7 的错。

    如果开放 Web 支持者不提供赞美诗,他们就不能指望每个人都唱歌。

    2012 年 2 月 22 日 上午 08:37

    1. Robert Nyman

      pd,

      Mozilla 绝对代表了 Web 的政治部分,但我所谈论的与政治毫无关系,而是极其实际的——尽可能多地覆盖操作系统、Web 浏览器和设备。

      在支持方面:canvas 元素从 Firefox 第二版、Safari 3.1 版以及所有版本的 Google Chrome 和 Opera 9 版开始就已存在——这意味着很多很多年。直到 Internet Explorer 9 版才出现。

      localStorage 也是几乎相同的情况,尽管在 Internet Explorer 中早了一个版本。所以是的,其中很多本来可以在 Internet Explorer 7 中实现。它在 WHATWG 中,它也在所有其他 Web 浏览器中。

      但为什么还要担心过去?它已经存在,并且所有 Web 浏览器的支持都在不断改善。

      2012 年 2 月 22 日 下午 11:30

  9. Joan

    哇,我刚读完这篇文章,我在 https://github.com/jcreus/localcache 中做了类似的事情(不相关)。它允许存储 CSS、JavaScript 和图像,并充当缓存。

    2012 年 2 月 25 日 下午 11:31

    1. Robert Nyman

      很酷,感谢分享!
      下一步是利用 IndexedDB(如果可用)——如 https://hacks.mozilla.ac.cn/2012/02/storing-images-and-files-in-indexeddb/ 中所示。

      2012 年 2 月 26 日 上午 07:32

      1. Joan Creus

        好的!我会研究一下,看起来很酷(我之前没听说过)。它会带来优势吗?也许可以允许 10 MB?(本地 5 MB,数据库 5 MB)。或者速度改进?谢谢!

        2012 年 2 月 26 日 上午 07:49

        1. Robert Nyman

          使用 IndexedDB,存储限制取决于 Web 浏览器,但在 Firefox 中,您可以拥有 50 MB 的存储空间。如果您超出该限制,系统会要求用户批准,您可以拥有更多存储空间。

          IndexedDB 更适合存储结构化数据,并且考虑到 IndexedDB 是异步的,API 的性质不同,您应该在那里获得更好的性能。

          我们稍后将在本博客上发布一篇关于 localStorage 的更详细的博文。

          2012 年 2 月 26 日 下午 14:26

  10. Mihai Chereji

    您好,感谢您的文章,我将在开发的 WordPress 插件中简要使用它。

    我现在最关心的问题是,有没有办法真正将由 Web 应用程序在客户端硬盘上创建的特定文件下载下来(无需服务器交互)?基本上,我现在需要的是类似于 这个 库想要实现的东西,但要添加一些额外的功能。我已经绞尽脑汁好几天了,我想我会试一试,在这里写一下,因为这似乎有点相关。

    再次感谢。

    2012 年 2 月 29 日 下午 4:55

    1. Robert Nyman

      是的,如果您有任何数据 URL/base64 编码字符串,您需要在链接的库中使用这种方法才能保存实际文件。

      2012 年 3 月 1 日 上午 4:31

  11. Cezary Tomczyk

    就我个人而言,我不认为 localStorage 在这里适合用于图像。只需从服务器发送带有 “Expires” 标头的图片,浏览器就会将它们缓存在本地。

    2012 年 3 月 2 日 上午 2:23

    1. Robert Nyman

      与 Expires 标头的区别在于,您无法对它应用任何逻辑。一旦它们进入 Web 浏览器缓存,它们就必须过期或被清除。有了它,您可以选择任何您想决定的检查,例如获取哪张图片、同一张图片的不同版本等。

      2012 年 3 月 2 日 上午 2:53

      1. Cezary Tomczyk

        是的,这是真的。但是,只要不需要对图像进行任何逻辑操作,只需存储在本地浏览器缓存中就足够了。

        2012 年 3 月 2 日 上午 3:18

        1. Robert Nyman

          绝对的。这完全取决于您自己的用例。

          2012 年 3 月 2 日 上午 3:19

  12. mihai

    我使用 localStorage 来保存用户与浏览器交互时(重要的?)内容,但连接断开(然后,如果可能,稍后同步)。因此,从这种意义上说,它很重要。

    2012 年 3 月 2 日 上午 2:40

    1. Robert Nyman

      是的,同步是它的另一个方面。

      2012 年 3 月 2 日 上午 2:54

  13. Mohamed Jama

    很棒的文章,谢谢 Robert。
    我只是想知道是否有一种方法可以检查浏览器是否处于私密浏览模式,如果是,那么看看您有哪些选择。

    2012 年 6 月 27 日 上午 4:15

    1. Robert Nyman

      谢谢!
      我希望 支持私密浏览模式 中的信息能帮助您。

      2012 年 6 月 28 日 上午 2:23

  14. Rani

    我正在阅读这里的评论,看来我和你们中的一些人遇到了同样的问题。我从 Robert 的回复中得到了答案,所以现在我不用再担心了。不过,我担心的是 IndexedDB 是否适合结构化数据。感谢您今天让我茅塞顿开!

    2012 年 10 月 4 日 上午 6:35

    1. Robert Nyman

      很高兴您似乎找到了答案。

      2012 年 10 月 4 日 上午 6:39

  15. Sam

    我一直都在寻找将 Web 应用程序图像存储到新库的方法。localStorage 似乎是一个不错的选择,将图像转换为 Data URL 以在 location 中被接受并不难,所以我想我会选择这个。感谢您的信息!

    2012 年 11 月 17 日 下午 9:22

  16. ben

    您好,最后一个选项很棒!有没有办法让它跨浏览器兼容?

    2012 年 12 月 6 日 上午 8:49

    1. Robert Nyman

      不幸的是,一些功能依赖于 Web 浏览器的支持。

      2012 年 12 月 6 日 上午 8:58

  17. Sid

    我可以在 IE8 中看到图像。这意味着 IndexedDB 对我来说有效吗?此外,我无法在 Firefox 17 或 alpha 或 nightly 版本上运行任何 IDB 演示。在 Chrome 上可以正常运行。我尝试创建了一个新的配置文件,但仍然没有用。:( 我是不是哪里做错了?

    我也是在您的其中一篇博文中发表评论的那个人 ;)

    2012 年 12 月 19 日 上午 4:20

    1. Robert Nyman

      您可能指的是 将图像和文件存储在 IndexedDB 中。如果您这样做,它肯定不会在 IE8 中运行。不过,如果操作失败,它会显示一张普通图像。

      否则,它会从 IndexedDB 中获取同一张图像,然后替换页面上的当前图像。因此,使用 Web 浏览器的开发者工具来检查图像的 src 属性。

      我刚刚在 Firefox Aurora 中测试了 IndexedDB 演示,它运行正常。如果问题仍然存在,请 提交错误报告

      2012 年 12 月 19 日 下午 4:09

本文的评论已关闭。