【问题标题】:Cross-browser implementation of "HTTP Streaming" (push) AJAX pattern“HTTP Streaming”(推送)AJAX 模式的跨浏览器实现
【发布时间】:2010-11-09 21:21:54
【问题描述】:

客户端从服务器请求网页。然后 Clent 要求进行额外的计算;服务器执行一系列计算并在部分结果可用时立即发送(文本格式,每行包含单独的完整项目)。客户端使用服务器提供的信息更新网页(使用 JavaScript 和 DOM)。

这似乎符合 Ajaxpatterns 网站的 HTTP Streamingcurrent 版本)模式。

问题是如何以跨浏览器(与浏览器无关)的方式进行操作,最好不使用 JavaScript 框架,或者使用一些轻量级框架,如 jQuery。

问题始于以跨浏览器方式生成 XMLHttpRequest,但我认为主要是并非所有浏览器都正确实现 onreadystatechangefrom XMLHttpRequest;并非所有浏览器都会在每个服务器刷新时调用 onreadystatechange 事件(顺便说一句。如何从 CGI 脚本(在 Perl 中)强制服务器刷新?)。 Ajaxpatterns 上的示例代码通过使用计时器来处理这个问题;如果我检测到来自onreadystatechange 的部分响应,我应该放弃计时器解决方案吗?


添加于 2009 年 8 月 11 日

当前解决方案:
我使用以下函数创建 XMLHttpRequest 对象:

function createRequestObject() {
        var ro;
        if (window.XMLHttpRequest) {
                ro = new XMLHttpRequest();
        } else {
                ro = new ActiveXObject("Microsoft.XMLHTTP");
        }
        if (!ro)
                debug("Couldn't start XMLHttpRequest object");
        return ro;
}

如果我要使用一些(最好是轻量级的)JavaScript 框架,比如 jQuery,如果用户选择不安装 jQuery,我希望有备用。

我使用下面的代码来启动 AJAX;使用setInterval 是因为某些浏览器仅在服务器关闭连接后(可能需要长达数十秒)才调用onreadystatechange,而不是在服务器刷新数据时(大约每秒或更频繁)。

function startProcess(dataUrl) {
        http = createRequestObject();
        http.open('get', dataUrl);
        http.onreadystatechange = handleResponse;
        http.send(null);

        pollTimer = setInterval(handleResponse, 1000);
}

handleResponse 函数是最复杂的一个,但它的草图如下所示。可以做得更好吗?如何使用一些轻量级的 JavaScript 框架(如 jQuery)来完成?

function handleResponse() {
    if (http.readyState != 4 && http.readyState != 3)
        return;
    if (http.readyState == 3 && http.status != 200)
        return;
    if (http.readyState == 4 && http.status != 200) {
        clearInterval(pollTimer);
        inProgress = false;
    }
    // In konqueror http.responseText is sometimes null here...
    if (http.responseText === null)
        return;

    while (prevDataLength != http.responseText.length) {
        if (http.readyState == 4  && prevDataLength == http.responseText.length)
            break;
        prevDataLength = http.responseText.length;
        var response = http.responseText.substring(nextLine);
        var lines = response.split('\n');
        nextLine = nextLine + response.lastIndexOf('\n') + 1;
        if (response[response.length-1] != '\n')
            lines.pop();

        for (var i = 0; i < lines.length; i++) {
            // ...
        }
    }

    if (http.readyState == 4 && prevDataLength == http.responseText.length)
        clearInterval(pollTimer);

    inProgress = false;
}

【问题讨论】:

  • 您绝对应该将该代码示例添加为回复并将其标记为正确的!
  • "如果用户选择不安装 jQuery" ?
  • 嗨,刚刚遇到了您的解决方案,但恐怕它仍然无法与 IE 一起使用,因为当您尝试在请求仍未结束时获取 responseText 时,那么您将收到以下消息:“完成此操作所需的数据尚不可用”。

标签: javascript ajax streaming xmlhttprequest comet


【解决方案1】:

实际上,您链接到的解决方案根本不是 AJAX。他们称之为 HTTP 流,但它本质上只是长轮询。

在他们链接到的示例中,您可以很容易地使用 firebug 自己查看。打开网络面板 - 没有 XHR 条目,但加载原始页面只需 10 多秒。那是因为他们在幕后使用 PHP 来延迟 HTML 的输出。这就是长轮询的本质——HTTP 连接保持打开状态,周期性的 HTML 发送回是 javascript 命令。

不过,您可以选择使用 setTimeout() 或 setInterval() 在客户端完全进行轮询

一个 jQuery 示例

<script type="text/javascript">
  $(document).ready(function()
  {
    var ajaxInterval = setInterval( function()
    {
      $.getJSON(
        'some/servie/url.ext'
        , { sample: "data" }
        , function( response )
          {
            $('#output').append( response.whatever );          
          }
      );
    }, 10000 );  
  });
</script>

【讨论】:

  • 不是我想要的。服务器上的计算以纯文本格式生成输出。使用 XHR,我可以直接在客户端获得此响应(onreadystatechange on flush / timer)并根据我获得的部分数据编辑网页。
  • 什么不是你想要的?长轮询?我不推荐任何一种方法 - 我只是告诉你你的选择是什么。
  • 如果你想使用长池(Comet),你应该考虑使用 Meteor 服务器软件,因为 Apache 不是为这类事情而设计的。还有一个javascript库可以为你处理几乎所有的事情,我只是不记得它的名字,稍后会发布它。
【解决方案2】:

我会看看轨道

他们使用了几个基于配置和浏览器嗅探选择的彗星传输实现。

http://orbited.org/svn/orbited/trunk/daemon/orbited/static/Orbited.js

并寻找“Orbited.CometTransports”

后端实现必须匹配一些不同的传输,因此请查看服务器端的轨道。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-07
    • 2012-08-27
    • 2013-06-01
    相关资源
    最近更新 更多