18

在网格中显示实时数据(证券交易所、天气……)的更好方法是什么?
我使用这种方法:

setInterval(function(){
      jQuery("#list1").trigger('reloadGrid');
}, 5000);
4

1 回答 1

16

我觉得你的问题很有趣。我认为这个问题对于许多其他用户来说可能很有趣。所以我+1。

在常见的独立于浏览器的情况下,使用setInterval接缝是最好的方法。应该将结果保存setInterval在一个变量中以便能够使用clearInterval它来停止它。

另一个小的改进是使用[{current:true}](有关详细信息,请参阅答案)作为 的第二个参数trigger

var $grid = jQuery("#list1"), timer;

timer = setInterval(function () {
    $grid.trigger('reloadGrid', [{current: true}]);
}, 5000);

它将在重新加载网格期间保存选择。

许多新的网络浏览器现在支持WebSocket。因此,如果网络浏览器支持它,最好使用这种方式。如果数据没有在服务器上更改并防止服务器永久池化,则可以跳过不必要的网格重新加载。

在我看来,一种更常见的方式也很有趣。如果可以使用网格数据最后更改的某种时间戳,则可以验证数据是否已更改。为此,可以在服务器上使用ETag或一些通用的附加方法。

当前填充 jqGrid 的jQuery.ajax的成功回调允许您使用实现回调来修改服务器响应,但它不允许您根据值停止 jqGrid 刷新(它将在当前的 jqGrid 代码中)。对 jqGrid 代码行的小修改将允许您在服务器上的数据未更改的情况下停止 jqGrid 刷新。可以测试(在 jqGrid 的当前代码中)或测试(在当前 jqGrid 代码中)304。重要的是要使用该场景,您应该使用option 和 set和beforeProcessingjqXHR.satusxhr.statustextStatusst"notmodified"jqXHR.satusxhr.statusprmNames: { nd:null }ETagCache-Control: private, max-age=0(有关更多信息,请参见此处此处此处)。

更新:我尝试根据我最后的建议创建演示项目,并发现它并不像我上面描述的那么容易。尽管如此,我还是让它工作了。困难在于无法从 jQuery.ajax 内部的服务器响应中看到 304 代码。原因是XMLHttpRequest 规范中的以下位置

对于作为用户代理生成的条件请求的结果的304 Not Modified响应,用户代理必须像服务器给出具有适当内容的200 OK响应一样行事。用户代理必须允许作者请求标头覆盖自动缓存验证(例如If-None-MatchIf-Modified-Since),在这种情况下, 必须传递304 Not Modified响应。

因此,人们在处理程序内部看到200 OK状态,而不是从服务器响应中看到304 Not Modified 。似乎只从缓存中获取完整响应,包括所有 HTTP 标头。所以我决定改变对缓存数据的分析,只是从最后一个 HTTP 响应中保存为新的 jqGrid 参数,并用保存的数据测试新响应的。success$.ajaxXMLHttpRequestETagETag

我看到你使用 PHP(我不使用 :-()。不过我可以阅读和理解 PHP 代码。我希望你能以同样的方式阅读 C# 代码并理解主要思想。所以你将能够在 PHP 中实现相同的功能。

现在我描述我做了什么。首先,我修改了使用回调的 jqGrid 源代码beforeProcessing

if ($.isFunction(ts.p.beforeProcessing)) {
    ts.p.beforeProcessing.call(ts, data, st, xhr);
}

if ($.isFunction(ts.p.beforeProcessing)) {
    if (ts.p.beforeProcessing.call(ts, data, st, xhr) === false) {
        endReq();
        return;
    }
}

它将允许从返回 falsebeforeProcessing跳过数据刷新 - 跳过数据处理。我在演示中使用的实现beforeProcessing基于用法ETag

beforeProcessing: function (data, status, jqXHR) {
    var currentETag = jqXHR.getResponseHeader("ETag"), $this = $(this),
        eTagOfGridData = $this.jqGrid('getGridParam', "eTagOfGridData");
    if (currentETag === eTagOfGridData) {
        $("#isProcessed").text("Processing skipped!!!");
        return false;
    }
    $this.jqGrid('setGridParam', { eTagOfGridData: currentETag });
    $("#isProcessed").text("Processed");
}

div 中的线条$("#isProcessed").text("Processed");或线条$("#isProcessed").text("Processing skipped!!!");"Processed""Processing skipped!!!"文本,我用来直观地指示来自服务器的数据用于填充网格。

在演示中,我显示了两个具有相同数据的网格。我用来编辑数据的第一个网格。第二个网格每秒从服务器中提取数据。如果服务器上的数据未更改,则 HTTP 流量如下所示

HTTP 请求:

GET http://localhost:34336/Home/DynamicGridData?search=false&rows=10&page=1&sidx=Id&sord=desc&filters= HTTP/1.1
X-Requested-With: XMLHttpRequest
Accept: application/json, text/javascript, */*; q=0.01
Referer: http://localhost:34336/
Accept-Language: de-DE
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; LEN2)
Host: localhost:34336
If-None-Match: D5k+rkf3T7SDQl8b4/Y1aQ==
Connection: Keep-Alive

HTTP 响应:

HTTP/1.1 304 Not Modified
Server: ASP.NET Development Server/10.0.0.0
Date: Sun, 06 May 2012 19:44:36 GMT
X-AspNet-Version: 4.0.30319
X-AspNetMvc-Version: 2.0
Cache-Control: private, max-age=0
ETag: D5k+rkf3T7SDQl8b4/Y1aQ==
Connection: Close

因此,如果数据未更改,则不会从服务器传输任何数据。如果数据发生更改,HTTP 标头将开始HTTP/1.1 200 OK并包含ETag新修改的数据以及数据页本身。

可以使用导航器的“刷新”按钮手动刷新网格数据,也可以使用每秒执行的“开始自动刷新”按钮刷新网格数据$grid1.trigger('reloadGrid', [{ current: true}]);。页面看起来像

在此处输入图像描述

我用颜色框在页面底部标记了最重要的部分。如果有一个loadui: "disable"选项,那么在拉动服务器期间根本看不到网格上的任何变化。如果有人评论了一个选项,即会在很短的时间内看到“正在加载...” div,但没有网格包含会闪烁

启动“自动刷新”后,主要会看到如下图

在此处输入图像描述

如果要更改第一个网格中的某些行,则第二个网格将在一秒钟内更改,并且将看到"Processed"文本,该文本将在一秒钟内更改为"Processing skipped!!!"文本。

服务端对应的代码(我用的是ASP.NET MVC)大多如下

public JsonResult DynamicGridData(string sidx, string sord, int page, int rows,
                                  bool search, string filters)
{
    Response.Cache.SetCacheability (HttpCacheability.ServerAndPrivate);
    Response.Cache.SetMaxAge (new TimeSpan (0));

    var serializer = new JavaScriptSerializer();
    ... - do all the work and fill object var result with the data

    // calculate MD5 from the returned data and use it as ETag
    var str = serializer.Serialize (result);
    byte[] inputBytes = Encoding.ASCII.GetBytes(str);
    byte[] hash = MD5.Create().ComputeHash(inputBytes);
    string newETag = Convert.ToBase64String (hash);
    Response.Cache.SetETag (newETag);
    // compare ETag of the data which already has the client with ETag of response
    string incomingEtag = Request.Headers["If-None-Match"];
    if (String.Compare (incomingEtag, newETag, StringComparison.Ordinal) == 0) {
        // we don't need return the data which the client already have
        Response.SuppressContent = true;
        Response.StatusCode = (int)HttpStatusCode.NotModified;
        return null;
    }

    return Json (result, JsonRequestBehavior.AllowGet);
}

我希望代码的主要思想对于不仅使用 ASP.NET MVC 的人来说也很清楚。

您可以在此处下载该项目。

更新:我发布了功能请求以允许通过返回值beforeProcessing来中断服务器响应的处理。false相应的更改已经包含在主 jqGrid 代码中(参见此处)。所以 jqGrid 的下一个版本将包含它。

于 2012-05-05T12:45:13.703 回答