我的页面是否从浏览器缓存中加载?

16

我在一个页面上有一个“新项目”徽章,我希望在从缓存加载页面时立即更新它(即当点击“返回”或“前进”返回到此页面时)。如何实现最佳效果?

设置非常简单。应用程序的布局每8秒钟查找新项目,并相应地更新徽章和项目列表。

$(function() {
    setInterval( App.pollForNewItems, 8000 );
});

当有人离开此页面查看项目的详细信息时,可能会发生很多事情。在任何用户查看它们之前,这些东西都是“新的”,并且应用程序很可能同时有几个用户使用(这种工作流程适用于呼叫中心或支持票务)。

为了确保徽章始终是最新的状态,我已经:

$(window).bind('focus load', function ( event ) {
    App.pollForNewItems();
});

虽然这样可以运作,但是只有在页面从缓存中加载时,通过“load”来轮询新项目才有用。是否有一种可靠的跨浏览器方式来判断页面是否从缓存加载?

5个回答

16

这个解决方案似乎在Firefox中不起作用?是否也有Firefox的解决方法? - Ralph
我问题的最佳答案!! - M Gholami
@Ralph 在我的 macOS 10.13 上的 Firefox 61 中它可以正常工作。 - John

8
您可以要求网络浏览器不缓存页面。请尝试使用以下HTTP头部:
```html

您可以要求网络浏览器不缓存页面。请尝试使用以下HTTP头部:

```
Cache-control: no-cache
Cache-control: no-store
Pragma: no-cache
Expires: 0

特别地,Cache-control: no-store 很有趣,因为它告诉浏览器根本不要将页面存储在内存中,从而防止在按下“后退/前进”按钮时加载过期的页面。

如果您这样做,就不必在页面加载时轮询数据。


1
我甚至没有考虑过缓存头!只要性能不受影响,这可能是正确的方法(我想确保它不会强制UA始终下载应该在整个应用程序中缓存的共享资源,例如JS、CSS、图像)。虽然这是问题的一个解决方案,但我仍然很好奇是否可以通过JS检测页面是否从缓存加载。有什么想法吗? - Blackcoat
我不知道是否有办法判断页面是否来自缓存。不过,@jball提出了正确的想法,可以检测页面呈现的日期。 - Jacob
这些变量应该在哪里设置? - YakovL

7

一个部分的hacky解决方案是在服务器上设置一个当前时间的变量,并在页面顶部设置一个当前客户端时间的变量。如果它们的差异超过一定阈值(1分钟?),那么您可以假设这是一个缓存页面加载。

示例JS(使用ASP.Net语法进行服务器端):

var serverTime = new Date('<%= DateTime.Now.ToUniversalTime().ToString() %>');
var pageStartTime = Date.UTC(new Date());
var isCached = serverTime < pageStartTime &&
               pageStartTime.getTime() - serverTime.getTime() > 60000;

或者,在客户端使用cookie(假设启用了cookie),您可以检查当前页面版本的唯一密钥的cookie。如果不存在,则为其编写一个cookie,并在访问任何其他页面时,该cookie的存在显示它正在从缓存中加载。

例如(假设某些cookie助手函数可用)

var uniqueKey = '<%= SomeUniqueValueGenerator() %>';
var currentCookie = getCookie(uniqueKey);
var isCached = currentCookie !== null;
setCookie(uniqueKey); //cookies should be set to expire 
                      //in some reasonable timeframe

1
我不会指望服务器和客户端能够非常好地同步 :/ - Matchu
问题在于你假设时钟同步。JS中的时间是由本地计算机的时间确定的,这可能与服务器的时间有很大的差异。 - Yahel
@Matchu,同步是一个棘手的问题,如果不生成另一个调用来计时延迟,就很难解决。 - jball
有趣!虽然这对我的情况实际上有效,但我仍然想知道是否有跨浏览器的解决方案来找出页面是否真正从缓存中加载。这在JS中是否可能? - Blackcoat
@Blackcoat - 你也许可以用 cookie 做类似的事情……我会看看能否提供一个例子。 - jball
是的,尽管这可能会比当前的解决方案影响性能更多。我担心当不使用缓存时,不必要的 $(window).bind('load') 处理程序的开销。每个 HTTP 请求都将发送额外的 cookie 到域,因此如果可能的话,我想避免它们。但你是对的,它们将完成告诉我们所需知道的任务(同其他形式的本地存储一样,尽管它们不是跨浏览器的)。 - Blackcoat

0

个人而言,我会为每个元素设置包含项目 ID 的数据属性。

例如:

<ul>
  <li data-item-id="123">Some item.</li>
  <li data-item-id="122">Some other item.</li>
  <li data-item-id="121">Another one..</li>
</ul>

你的App.pollForNewItems函数将会获取第一个元素的data-item-id属性(如果最新的在前面),并将其与原始请求一起发送到服务器。

然后,服务器将仅返回WHERE id > ...的项目,您可以将它们添加到列表中。

我仍然不明白为什么你想知道浏览器是否有缓存版本的页面。

此外,绑定到load而不是ready是否有原因?

  • Christian

基督徒,好的建议,尽管应用程序已经完全按照您描述的方式进行了操作(尽管时间戳与ID进行比较)。至于使用“load”而不是“ready”,我也想绑定到“focus”事件,并保持代码DRY。'Ready'是由jQuery构造的人工事件,它只能绑定到文档上。如果您尝试$(document).bind('focus ready', { ... }),则处理程序将永远不会触发“focus”事件。由于从缓存中加载的页面的“ready”和“load”事件之间的时间差应该可以忽略不计,“load”在这里就足够了。 - Blackcoat

0

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