【问题标题】:Possible to cache JSON to increase performance / load time?可以缓存 JSON 以提高性能/加载时间吗?
【发布时间】:2013-07-10 21:08:34
【问题描述】:

我正在使用 JSON 文件来自动填充下拉列表。它绝不是巨大的(3000 行并且还在增长),但刷新页面所花费的时间变得非常明显。

第一次加载页面时,会读取 JSON,这取决于用户选择的选项决定了 JSON 的哪一部分用于填充下拉列表。

然后在每次刷新或菜单选择之后加载它。是否有可能以某种方式缓存这些值以防止需要一次又一次地重新加载?

谢谢。

编辑:更多信息: 它本质上是一个单位转换器。 JSON 包含所有详细信息。例如,当用户选择“临时”时,会拨打电话并填充列表。转换完成后,您可以花一整天时间运行临时转换,它们会很好,但每次用户更改转换类型时,现在长度,页面都会刷新并花费大量时间。

【问题讨论】:

  • 根据您的服务器端语言,您是否考虑过会话/cookies/数据库/平面文件存储?
  • 您好 Andrew,我正在使用 PHP 服务器端。我确实简要地考虑了一个数据库,但现在正在使用 JSON,我必须坚持使用这种方法。
  • 我的意思是临时存储 - 从任何来源获取您的 json 数据,然后将它们临时存储到会话中,例如,以避免重新加载它们
  • 一个简单的单位转换器如何需要约 3000+ 项数据?顺便说一句,您应该去掉所有空格,这样 JSON 就不会以“行”为单位,而只是以 KB 为单位。
  • 我很困惑,您是要缓存 JSON 还是渲染下拉列表的 HTML?根据您发布的那个小提琴,看起来您加载了 JSON 服务器端并使用它来呈现 HTML。我的猜测是加载时间更有可能是 HTML 在网络中传播,或者浏览器绘制了大量的下拉列表,而不是读取 JSON 的服务器端代码。

标签: javascript json


【解决方案1】:

不幸的是,我不知道 PHP 中有标准化的全局缓存机制。 This 文章说,第三方加速器 Optimizer Plus 从版本 5.5 开始包含在核心 PHP 中。不确定您使用的是什么版本,但您可以尝试一下。

另一方面,您是否考虑过 andrew 指出的文件存储?我认为它与$_SESSION 在这种情况下真的可以帮助你。让我举个例子来处理你现有的 JSON 数据:

服务器端

将您的 JSON 数据存储在 PHP 服务器上的 .json 文件中:

{
    "data": "some data",
    "data2": "more data",
    "data3": [
        ...
     ],
     etc.
}

注意:确保正确格式化您的 JSON 数据。请记住,所有字符串必须用 double 引号 " 括起来。

在 PHP 中,使用 if 语句来决定适当的操作:

error_reporting(E_ALL);
ini_set("display_errors", "On");
session_start();

if(isset($_SESSION['dataCache'])) {
    echo json_encode($_SESSION['dataCache']);
} else {
    $file = 'data.json';
    if (!is_file($file) || !is_readable($file)) {
        die("File not accessible.");
    }
    $contents = file_get_contents($file);
    $_SESSION['dataCache'] = json_decode($contents, true);
    echo $contents;
}

所以让我们再深入研究一下上面的编码。简而言之,这就是我们正在做的事情:

  1. 打开错误报告并启动会话支持。
  2. 检查我们是否已经为该用户读取了文件。
  3. 如果是这样,请从存储中提取值并将其回显并退出。如果没有,请继续下面。
  4. 保存文件名并做一些错误检查以确保 PHP 可以找到、打开和读取文件的内容。
  5. 读取文件内容。
  6. 将解码后的 json(由于传递给 `json_decode` 的 `true` 参数不是数组)保存到您的 `$_SESSION` 变量中。
  7. 将内容回显到屏幕上。

这将节省您解析 JSON 数据和/或在服务器上手动构建它的时间和麻烦。它将被缓存给用户session,以便他们可以使用它。

客户端

我假设您正在使用ajax 来获取信息?如果不纠正我,但我假设这就是你的一些 JavaScript 发挥作用的地方。如果是这样,您可以考虑这样做:

从服务器返回时,将返回的数据存储在用户浏览器的sessionStorage中:

$.ajax({
    ...
    success: function (res) {
        localStorage.setItem("dataCache", JSON.stringify(res));
    },
    ...
});

或者如果你使用 promise 对象:

$.ajax({
    ...
}).done(function (res) {
    localStorage.setItem("dataCache", JSON.stringify(res));
});

当你需要阅读时,你可以做一个简单的测试:

var data;
// This returns null if the item is not in local storage.
// Since JavaScript is truthy falsy, it will be evaluated as false.

if(localStorage.getItem("dataCache")) {
    data = JSON.parse(localStorage.getItem("dataCache"));
} else {
    // Make ajax call, fetch object and store in localStorage in the success or done callbacks as described above
}

注意事项:

localStorage 是 HTML5 中的一项新功能,因此尚未在所有浏览器上完全支持。然而,大多数主要的都这样做,甚至可以追溯到 IE8(我认为)。但是,对于这些浏览器每个站点需要容纳多少容量没有标准化的大小限制。

考虑到这一点很重要。我可以保证您可能无法将整个 30,000 行字符串存储在 localStorage 中。但是,您可以以此为起点。结合服务器端解决方案,您应该会看到性能提升。

希望这会有所帮助。

【讨论】:

  • 太棒了!谢谢!大量信息和附加细节使其更易于消化。阿贾克斯,暂时对我来说是陌生的。要访问我使用的数据:jsfiddle.net/wKCBD。如果我能够将它们结合起来,我想我会离涅槃更近一步。我已经在设置会话变量,因为用户可以选择登录等,我认为我可以将其附加到该会话而不是创建一个新会话是正确的。 (会话也有点陌生:))
  • @SteveGreen 我还在努力磨练我的 ajax 技能。这确实需要一些练习,但使用它时你肯定会看到一些很好的结果。比重新加载整个页面要快得多。祝你好运,快乐的编码伙伴!希望你达到你的编码必杀技。 :)
  • 我认为 OP 既不需要 PHP 也不需要 DOMstorage 缓存。只需发送适当的 HTTP 缓存标头就足够了。
  • @Bergi 这是一个很好的观点。 :) 当我在本地服务器上测试上述解决方案时,我没有尝试过,但这可能也会有所帮助和/或完全是另一种可能的解决方案。很好的观点。
  • @Bergi,您能详细说明一下吗?
【解决方案2】:

我使用browser's cache 来确保我的大量 JSON 在每个会话中只下载一次。我在 ASP.NET 中编程,但我确信 PHP 具有相同的机制:

  1. 在会话开始时,我生成一个随机字符串作为动态 JavaScript 的会话密钥。此密钥存储在密钥JsonSessionID 下的ASP.NET session state 中。这样我就可以在我的页面标记中引用它。
  2. 我有一个“通用 http 处理程序”(an ashx file),当浏览器调用它时,它会返回一个包含我的 JSON 的 .js 文件。
  3. 在我的 HTML 中,我包含了动态脚本: <script type="text/javascript" src="/dynamicJSON.ashx?v=<%= JsonSessionID %>"></script>

浏览器会自动缓存作为脚本包含的所有 URL。下次要求浏览器从 URL 加载缓存脚本时,它只会从本地磁盘加载文件。这包括像这样的动态页面。

通过在其中添加?v=,我ensure that the JSON is updated once per session

编辑

我刚刚意识到您的 JSON 可能是静态的。如果是这种情况,您只需将 JSON 放入 HTML 中包含的静态 .js 文件,浏览器就会缓存它。

// conversionData.js
var conversionData = { "a":1,"b":2,"c":3 };

当您包含 conversionData.js 时,conversionData 变量将在您页面的其余 JavaScript 的范围内,这些 JavaScript 会动态更新下拉列表。

编辑 2

如果您提供静态文件,则此 blog post 具有基于文件的修改日期属性的缓存清除的良好模式。即文件仅在服务器上更改时才会下载。

除了每个会话之外,我还没有找到一种通过数据库查找表创建的缓存清除 JSON 的好方法。这并不理想,因为数据库可能会在会话中更改。

【讨论】:

  • 仅当新单元可用(JSON 更新)时才破坏缓存可能比每次会话破坏更易于缓存。当然取决于更新率。不过,+1!
  • @Bergi:确实如此。我在我的答案中添加了另一个编辑,关于如何在每次静态文件更改时缓存一次。
【解决方案3】:

一旦您将 JSON 数据解码为一个对象,您就可以保留该对象,它应该至少会持续到页面重新加载。

如果您想在重新加载之间保持不变,您可能需要查看 HTML5 的 localStorage 等。

你需要想出一个年龄策略,也许只是把当前日期也放在那里,这样你就可以比较它并根据需要过期。

【讨论】:

  • 嗨劳埃德,我仍然不确定这会有什么帮助。它本质上是一个单位转换器。 JSON 包含所有详细信息。例如,当用户选择“临时”时,会拨打电话并填充列表。转换完成后,您可以发送全天运行的临时转换,它们会很好,但是每次用户更改转换类型时,现在长度,页面都会刷新并花费大量时间。 - 将此添加到帖子中,以获得更多信息。
【解决方案4】:

我建议将您的 json 数据存储到会话中。在第一页加载时,您可以编写一个脚本来获取您的 json 数据,然后将它们存储到会话中。 在每个页面加载/刷新之后,您可以检查我们的会话以决定做什么 - 使用会话数据或再次获取您的 json 数据。

这种方法适合我处理小规模数据(例如:一系列产品 - 颜色 - 尺寸 - 价格)。

根据您的数据,您应该测试加载时间。

【讨论】:

  • 谢谢,我想我会试一试的。不要以为您可以告诉他们如何将其存储为会话?在上一个建议之后,我用谷歌搜索了一下,但没有发现任何有用的东西。这是我当前获取 JSON 的脚本:jsfiddle.net/wKCBD
【解决方案5】:

这是一个简单的技巧:

使用参数“bla-bla.html”创建对 php 文件的调用作为 GET 请求 或“bla-bla.css”...您知道,它使浏览器认为它不是 php,而是“html”或“c​​ss”。浏览器会缓存它。

要验证该技巧是否有效 - 转到浏览器开发面板的“网络”选项卡,您将在那里看到“类型”列和“已传输” - 而不是那里有 php 和实际大小,你会发现“html”和“(缓存)”

当您将诸如“blah-blak.html”之类的参数传递给 php 文件并期望它不会被缓存时,这也很重要。嗯,会缓存的。

在 FireFox Quantum 57.0.1 (Mac 64bit) 上测试

附:

Mac 上的 Chrome 63 能够在这种情况下识别真实的文件类型。所以它不能被愚弄。

【讨论】:

    【解决方案6】:

    在这里开箱即用:

    但是如果您的列表有 3000 行并且还在增长(如您所说) 你能确定它的最大尺寸吗?

    假设答案是 10,000(最多)个项目;那么你真的需要一个ajax调用吗? 您可以通过页面直接传输数据

    (当然,取决于您的架构,您可能会提出不同的解决方案)

    【讨论】:

    • 嗨,我预计最大尺寸约为 30,000 左右。
    • @史蒂夫格林。 1.您是否需要全部加载它们(以帮助自动完成)? 2 是那些小字符串(例如 20 - 25 个字符)?如果是这样,我的想法适用...抛弃 ajax 并将它们与页面一起加载
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-13
    相关资源
    最近更新 更多