问题 可以缓存JSON以增加性能/加载时间吗?


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

第一次加载页面时,将读取JSON,具体取决于用户选择的选项指示JSON的哪个部分用于填充下拉列表。

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

谢谢。

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


11202
2017-07-12 10:34


起源

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


答案:


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

另外,您是否将文件存储视为 安德鲁 指出?我认为它结合了 $_SESSION 在这种情况下真的可以帮到你。让我举一个可以使用现有JSON数据的示例:

服务器端

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

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

注意: 确保正确格式化JSON数据。记住必须包含所有字符串  报价 "

在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(我认为)。但是,对于每个站点需要保留多少浏览器,没有标准化的大小限制。

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

希望这可以帮助。


11
2017-07-12 13:04



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


我用 浏览器的缓存 确保我的大块JSON每个会话只下载一次。我在ASP.NET中编程,但我确信PHP具有相同的机制:

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

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

通过添加 ?v= 在那里,我 确保每个会话更新一次JSON

编辑

我刚刚意识到你的JSON可能是静态的。如果是这种情况,您可以将您的JSON放入HTML中包含的静态.js文件中,浏览器将对其进行缓存。

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

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

编辑2

如果您要提供静态文件,请执行此操作 博客文章 具有基于文件的日期修改属性的缓存清除的良好模式。即只有在服务器上更改文件时才下载文件。

我还没有找到一个很好的方法来缓存通过数据库查找表创建的缓存,而不是每个会话。这是不理想的,因为数据库可能会在会话期间发生变化。


4
2017-07-12 13:24



仅当新单元可用时(JSON更新)才能缓存高速缓存可能比每个会话破坏更加缓存友好。当然取决于更新率。还是,+1! - Bergi
JSON将是静态的。这么多选择! :) - null
@Bergi:那是真的。我添加了另一个编辑,我的答案是每次静态文件更改时如何缓存一次。 - Walter Stabosz


一旦你将你的JSON数据解码成一个对象,你可以保持对象,它应该持续到页面重新加载为止。

如果你想在重新加载之间坚持下去,你可能想看看HTML5 localStorage 等等

您需要提出一个年龄策略,也许只是将当前日期转储到那里,以便您可以比较它并根据需要过期。


0
2017-07-12 10:39



嗨劳埃德,我还不确定这会有什么帮助。它本质上是一个单位转换器。 JSON包含所有细节。例如,当用户选择“Temp”时,进行呼叫并填充列表。转换完成后,您可以发送全天运行的临时转换,但它们会很好,但每次用户更改转换类型时,现在长度,页面都会刷新并占用大量时间。 - 添加此内容以发布更多信息。 - null


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

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

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


0
2017-07-12 11:56



谢谢,我想我会试一试。不要以为你可以告诉em如何存储会话?我在之前的建议之后搜索了一下但没有找到任何有用的东西。这是我当前获取JSON的脚本: jsfiddle.net/wKCBD - null


这是一个简单的黑客:

使用参数“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能够识别真实文件类型。所以它不能被愚弄。


0
2017-12-20 02:13





开箱即用:

但如果你的名单有3000行而且还在增长(如你所说) 你有可能确定它的最大尺寸吗?

假设答案是10,000(最大)项目;那你真的需要一个ajax电话吗? 您可以直接将数据传输到页面

(当然,根据你的架构,你可以提出不同的解决方案)


-1
2017-07-12 10:49



嗨,我预计最大尺寸约为30,000左右。 - null
@Steve Green。 1.无论如何,你是否需要加载所有这些(以帮助自动完成)? 2是那些小字符串(例如20 - 25个字符)?如果是这样我的想法适用... ditch ajax并加载它们与页面 - Zo72