网格中的实时数据 - 更好的方法

Ber*_*aud 18 jqgrid

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

setInterval(function(){
      jQuery("#list1").trigger('reloadGrid');
}, 5000);
Run Code Online (Sandbox Code Playgroud)

Ole*_*leg 16

我觉得你的问题非常有趣.我认为这个问题对许多其他用户来说可能很有意思.所以来自我的+1.

setInterval在常见的浏览器独立案例中,使用接缝是最好的方法.一个原因应该是保存setInterval变量中的结果以便能够用clearInterval它来阻止它.

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

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

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

它将在重新加载网格时保存选择.

许多新的Web浏览器现在都支持WebSocket.因此,如果Web浏览器支持它,最好使用这种方式.在这种情况下,如果服务器上的数据没有更改,并且阻止了服务器的永久池,则可以跳过不需要的网格重新加载.

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

填充jqGrid 的jQuery.ajax当前成功回调允许您使用实现回调来修改服务器响应,但它不允许您根据值停止jqGrid刷新(它将在当前的jqGrid代码中).对jqGrid代码的小修改将允许您在服务器上未更改数据的情况下停止jqGrid刷新.可以测试(在当前的jqGrid代码中)或测试(在当前的jqGrid代码中)304.这一点很重要,要使用你应该使用方案选项,并设置和(见这里,这里这里了解更多信息).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的内部状态success的处理$.ajax,而不是304未修改来自服务器的响应.似乎XMLHttpRequest从缓存中获取完整响应,包括所有HTTP头.因此,我决定更改缓存数据的分析,只是ETag将最后一个HTTP响应保存为新的jqGrid参数,并ETag使用保存的数据测试新响应.

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

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

if ($.isFunction(ts.p.beforeProcessing)) {
    ts.p.beforeProcessing.call(ts, data, st, xhr);
}
Run Code Online (Sandbox Code Playgroud)

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

它将允许返回false beforeProcessing以跳过刷新数据 - 跳过数据处理.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");
}
Run Code Online (Sandbox Code Playgroud)

我用来直观地指示来自服务器的数据用于填充网格的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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

因此,如果数据未更改,则不会从服务器传输任何数据.如果数据已更改,则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);
}
Run Code Online (Sandbox Code Playgroud)

我希望代码的主要思想也适用于那些不仅使用ASP.NET MVC的人.

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

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