【问题标题】:How to detect if a page should be updated? [closed]如何检测页面是否应该更新? [关闭]
【发布时间】:2014-03-20 08:53:57
【问题描述】:

我在一个页面中有一个显示摘要数据的表格。
这些数据来自一个汇总数据库表。如果基础表得到更新,我需要刷新页面中显示的此表。
我知道的方法是每 X 秒重新加载一次页面。
但我感兴趣的是在表格实际更新时更新表格。
什么是标准解决方案?我能想到的唯一方法是在表中添加一些额外的列,以使行 ID 已更新,并以某种方式每 X 秒在该列上“轮询”一次。我认为它可以工作,但它似乎是可怕的解决方案,我想知道解决这个(我假设是常见的)问题的标准方法是什么。

更新:
只是为了添加更多内容。我的问题不是那么笼统。我只有 1 个特定部分的代码可以更新表格,并且更新完全在我的控制之下。它不像一个由多个来源更新的表格

【问题讨论】:

  • 为什么要关闭?我能以某种方式改进这个问题吗?
  • 为此,您需要某种服务器端框架。在 .Net 中,我将创建一个 SignalR 应用程序(它利用 Web 套接字进行实时通信),然后设置对我的数据库表的依赖,当它的内容发生变化时会引发一个事件。
  • 这个问题非常广泛,有很多可能的解决方案。有了您的 2.3K 代表点,这里的人们通常认为您应该知道不要在不付出努力的情况下发布问题......
  • 总的来说,最简单的方法是创建一个setInterval() 并可能每 5 秒执行一次连续的 AJAX 调用。
  • @ChrisHardie:更新有帮助吗?

标签: javascript jquery ajax database http


【解决方案1】:

有很多不同的方法可以解决这样的问题。最好和最有效的解决方案将涉及您的服务器的一些帮助,以了解何时/发生了什么变化。以下是一些想法:

  1. 使用 websocket 连接到您的服务器,以便您的服务器可以在后端数据发生更改时发出通知,然后客户端可以请求新数据。

  2. 使用原始页面提供某种“最后一个事务 id”,然后在轮询间隔上使用 ajax 调用来询问服务器自从最后一个事务 id 以来数据是否发生了变化。如果是,请请求新数据。如果没有,什么都不做。这可以防止您在没有任何实际变化的情况下一遍又一遍地获取数据。

  3. websocket 的替代方案是对 http 推送的长轮询,也可以使用(特别是在不支持 websocket 的客户端中)允许服务器在有新数据时通知客户端。

【讨论】:

  • +1.我喜欢(2)。但是如何定义“最后一个事务ID”?它是“存储”在数据库级别的东西吗?
  • @Jim - 是的,最后一个事务 id 必须是您的数据库或服务器实现/支持的东西。
  • 这是我没有得到的部分。我正在使用 MySQL。那会是一个实际的事务 id 吗?在我的代码中,我只是在做 UPDATE TABLE SET...。还是某种“应用程序”构造?能否详细说明一下?
【解决方案2】:

通讯系统

您有多种方法可以创建一种自动更新的动态页面(例如 Facebook)。

  1. 基本。 最基本的方法是,就像你说的,每 X 秒轮询一次服务器(有一个 JavaScript 无限 $.ajax({}); 循环调用每个 X秒)查看服务器上是否有新事物。这是一个有效的解决方案,过去曾使用过。

  2. Push。 第二种方法也很常用,是long polling or push。如果您在后端使用异步框架(即 Node.js、Tornado、Twisted 等),您可以非常轻松地使用此解决方案,因为它几乎没有性能成本。对于 PHP 或 Django 等其他后端框架,这不是一个好方法,因为您为每个请求创建一个进程,该进程保持打开状态,直到某些内容更新或达到 Http 连接超时(人们将大部分时间,据我所见,长轮询上的 30 秒计时器)。

  3. 套接字。这是最新且最不受支持的方法。并非所有浏览器都可以访问 WebSocket。和以前一样,异步框架更适合这种方法。

如果您有一个基于 CGI 的后端框架(这意味着 WCGI、FastCGI 等),例如 Django、PHP、Flask 等,那么您最好采用第一种方法,这是最基本的方法。对于您的服务器而言,采用任何其他资源都是非常昂贵的资源。如果您有异步后端,那么第二种或第三种方法都可以。 我必须说,Web 套接字方法更难进入、正确编程和支持框架。

数据库系统

在您选择想要用作通信系统的系统后,您的数据库设计需要反映您需要执行的新查询类型。
假设用户想要查看自加载页面以来的所有新更改。

  • 一种简单的方法是在每一行上都有一个日期,即最后一次更改的时间。查询自上次查询时间以来更改的所有行。

  • 一个更复杂的方法是实现一个完整的通知系统。对于每个更改或新行,将添加一个关于它的新通知。您可以在用户和通知之间建立关系以了解他是否已经看过它,并安排每 24 小时执行一次作业以删除旧关系。但很快这一切都变得臃肿。我更喜欢在通知系统中使用 NoSQL 数据库(像 CouchDB 这样的 JSON 数据库)。您可以轻松更改文档的结构并为所有通知创建特定视图。它比关系数据库更宽松。如果您想知道用户加载页面后您的数据是否发生了变化,您所要做的就是查询通知的类型(您正在观察哪些数据/表以进行更改)并获取创建日期比上次更新的通知查询时间,也未查看。由于您的表格始终反映最后的状态,因此在页面加载时您查询表格,之后您只查询更改或此处称为通知。

我的个人看法

如果您有一个 CGI 后端,那么对于一个完整的通知系统,您需要在您的之上添加一个特定的后端结构,用于长轮询或套接字。不要忘记您的客户端还需要对如何对新的服务器处理程序做出反应有逻辑。为了快速获得结果,如果您的工作指定了这一点,您更适合在页面中仅使用一个脚本,该脚本每 1 分钟左右重新加载一次页面。

如果您已经在使用异步框架,则可以轻松添加通知功能,但需要对数据库进行大量工作,尤其是在通知位于关系数据库中时。如果您决定为此专门添加一个新数据库,则还需要在您的后端进行大量应用逻辑以及对其进行培训。

希望我能帮上忙,干杯!

【讨论】:

  • 关于 (1) 基本方法。我理解这一点,但我的 OP 是关于如何准确检测已更新内容的具体方法。您是否建议每 X 秒重新加载整个表?跨度>
  • 您必须为此在服务器端创建一个处理程序。除非您的客户端可以查询您的数据库(我想您将信息存储在那里),否则您需要创建一个处理程序来为您查询并返回已更改的内容。当然,如果您想支持“已更改”的系统,则需要根据该意图进行数据库设计。例如,在您的行上有一个日期,这是您最后一次修改它,然后在您的查询中有一个日期,以了解您最后一次查询更改的时间。
  • Of course if you want to support a "has changed" system 这正是我感兴趣的。我可以例如保留一个额外的列,该列仅在表的第一行中具有价值,例如最近更新的 ID,但这似乎是可怕的解决方案,我正在寻找替代方案
  • 这是一个“可怕的”非缩放解决方案,但它是最快的。我正在使用的另一种选择是完整的通知系统。当有新内容出现时,它会添加到通知表中(这就是您查询的内容)。一个简单的设计可以是this。我以前看过一个非常好的堆栈溢出,但找不到它的链接。对于通知,我总是使用 noSQL 数据库(对我来说是 CouchDB),它不会因关系而变得臃肿,而且更容易解决。
  • 所以在通知表中为添加/更新的每一行新表存储每个 id/每个用户?
【解决方案3】:

轮询是最简单的方法。它看起来像这样:

(function poll() {
  $.ajax('/myTableData', {
    success: function(data) {
        updateTable(data);
    },
    complete: function() {
       setTimeout(poll, 8000); //every eight seconds
    }
  });
})();

然后您将端点 /myTableData 添加到您的服务器。

支持实时协作的 Google Docs 在撰写本文时进行了民意调查。然而,更复杂的是,轮询是“长的”:它们持续多久,直到新数据到达,或者经过一定时间(例如 40 秒),以先到者为准。这减少了轮询的数量。

或者,您可以查看现代浏览器 (IE 10+) 支持的 websocket。

【讨论】:

  • 这种方法的问题(确实有效!)是您不必要地以随机间隔(N 秒)轮询更改。可能很难推断数据更改的频率以及用户停留在页面上的典型时间……尤其是在需求发生变化时。
  • 感谢您提供此代码示例。但是 updateTable 到底是什么?它会更新 whole 表吗?只有已更新的部分?但是我们转到我的原来的问题,我怎么知道哪些行需要更新?
【解决方案4】:

这是 WebSockets 的前提(http://socket.io 用于 shim)。您需要(如前所述)一个服务器(例如 Node.JS)来支持 WebSocket 功能——大多数现代 Web 浏览器都在客户端支持此 API。

Web Sockets API (http://www.w3.org/TR/2012/CR-websockets-20120920/) 允许浏览器不断地与服务器通信数据(反之亦然)。

如果更新了数据库记录,您可以设置触发器将此数据传送回客户端。以评论板系统(与我们在 StackOverflow 上使用的完全一样)为例——因为网络上已经有大量信息可用,我认为这里没有必要详细介绍。

进一步阅读和工具:

正如其他人所提到的,您可以使用 AJAX 通过 setInterval(首选)或 setTimeout 方法进行轮询。不要忘记创建一个变量来存储 set[Fn] 的 ID,以防您(或用户)希望取消它:

var pollID = window.setInterval(function poller(){ getAjaxData(); }, 2000);
if (noUpdate) window.clearInterval(pollID);

【讨论】:

  • pollID 是什么?
  • pollID 是用户代理(浏览器)在调用 setInterval 或 setTimeout 时生成的有点随机的数字。如果我没记错的话,它通常是一个介于 1 到 100000 之间的整数。实际数字并不重要......它只是一个参考,以便您可以停止执行 setInterval 或 setTimeout。
猜你喜欢
  • 1970-01-01
  • 2017-01-16
  • 2018-10-27
  • 1970-01-01
  • 1970-01-01
  • 2012-01-02
  • 2016-07-18
  • 2019-02-21
  • 1970-01-01
相关资源
最近更新 更多