Ajax Streaming是什么,可以起到什么作用?或许我给你举个例子你就会明白了,并且会喜欢上它

比如通过ajax请求一个安装脚本,此脚本可能需要执行1分钟,传统的ajax只有在页面执行完毕后才会得到执行情况,那么怎么可以让页面实时知道服务器上执行的状态呢?此时,Ajax Streaming就发挥作用了,可以帮你实现输出每个步骤的详细信息。

在服务器上,可通过特殊的处理,将每一个执行的步骤推送到浏览器。

这样就可以输出类似下面的信息了:

执行初始化成功…
开始执行步骤一
步骤一执行成功
步骤二开始
步骤二结束

全部执行完毕

PHP代码示例:

<?php
if (ob_get_level() == 0) ob_start();

// echo str_pad("", 1000);ob_flush();flush();    //兼容IE的堵塞,否则IE下只有执行完毕才会显示

for ($i = 0; $i<10; $i++)
{
        echo "<br> Line to show.";
        echo str_pad('',4096)."\n";    

        ob_flush();
        flush();
        sleep(1);
}
echo "Done.";
ob_end_flush();

上面的代码取自 http://php.net/manual/zh/function.flush.php

注意,nginx + php-fpm 模式需要在 nginx 的配置里加入

fastcgi_buffering of;

的配置

上面这样做后,大部分浏览器都可支持,但是,若此请求是在ajax中,则被称为Ajax Streaming,然后目前,经我测试Firefox,Chrome,Safari等都已支持,而IE不支持,看到有人说IE8支持,但我测试下来也是不支持的,所以在IE里需要寻求别的解决的方案,比如通过框架的方式是可以实现的。

在支持Ajax Streaming的浏览器中,不需要做特别的处理,每当浏览器收到新数据后,都会运行XMLHttpRequest的onreadystatechange方法,且XMLHttpRequest的状态readyState=3

例如:

xmlhttp=new XMLHttpRequest();
xmlhttp.XMLHttpRequest = function(){
   if (xmlhttp.readyState==3){
      alert(xmlhttp.responseText);
   }else if (xmlhttp.readyState==4){
      alert('ok');
   }
}

你会发现,当readyState==3的时候会被多此运行。

IE里只会执行1次,所以我采用了iframe的实现。普通的iframe会让浏览器产生一个loading进度条,这让人很不爽,所以采用了 http://infrequently.org/2006/02/what-else-is-burried-down-in-the-depths-of-googles-amazing-javascript/ 的方案。

通过创建一个new ActiveXObject(“htmlfile”);再特殊处理就可以不产生那个讨厌的加载进度了。

下面是我写的一个整合的代码,通过它完全模拟出了一个xmlhttp,

var self = this;
// 构造一个虚拟的xmlhttp对象
this.xmlhttp = {
    responseXML: null,
    responseText: '',
    responseType: null,
    response: '',
    status: 0,
    readyState: 0,
    method: 'POST',
    open: function(method, url) {
        this.method = method;
        var newurl = [];
        if (url.indexOf('#') != -1) {
            newurl = url.split('#');
        }
        else {
            newurl = [url];
        }
        if (newurl[0].indexOf('?') == -1) {
            newurl[0] += '?_ajax=true';
        }
        else {
            newurl[0] += '&_ajax=true';
        }
        url = newurl.join('#');
        this.url = url;
        this.ifrDiv.innerHTML = '<iframe id="myqee_ajax_iframe" onload="alert(888)" name="myqee_ajax_iframe"></iframe><form id="myqee_ajax_fram" target="myqee_ajax_iframe" action="' + url + '" method="POST"></form>';
        var objframe = this.obj.getElementById('myqee_ajax_iframe');
        var getdata = function() {
            if (objframe.readyState == 'loadinng') {
                if (self.xmlhttp.readyState == 0) {
                    self.xmlhttp.readyState = 1;
                    self.xmlhttp.onreadystatechange();
                }
            }
            else if (objframe.readyState == 'interactive') {
                if (self.xmlhttp.readyState == 0) {
                    self.xmlhttp.readyState = 1;
                    self.xmlhttp.onreadystatechange();
                }
                if (self.xmlhttp.readyState == 1) {
                    self.xmlhttp.readyState = 2;
                    self.xmlhttp.onreadystatechange();
                }
                if (self.xmlhttp.readyState == 2) {
                    self.xmlhttp.readyState = 3;
                }
                if (self.xmlhttp.response != objframe.contentWindow.document.body.innerHTML) {
                    self.xmlhttp.response = self.xmlhttp.responseText = objframe.contentWindow.document.body.innerHTML;
                    self.xmlhttp.onreadystatechange();
                }
            }
            else if (objframe.readyState == 'complete') {
                clearInterval(runtime);
                runtime = null;
                if (self.xmlhttp.response != objframe.contentWindow.document.body.innerHTML) {
                    self.xmlhttp.response = self.xmlhttp.responseText = objframe.contentWindow.document.body.innerHTML;
                    self.xmlhttp.onreadystatechange();
                }
                self.xmlhttp.readyState = 4;
                self.xmlhttp.status = 200;
                self.xmlhttp.onreadystatechange();
            }
        };
        var runtime = setInterval(getdata, 10);
    },
    send: function(data) {
        if (this.method == 'GET') {
            //GET方式最简单了
            this.obj.getElementById('myqee_ajax_iframe').src = this.url;
        }
        else {
            var newdata = data.split('&');
            var html = '';
            for (var i = 0; i < newdata.length; i++) {
                var index = newdata[i].indexOf('=');
                var k = decodeURIComponent(newdata[i].substr(0, index));
                var v = decodeURIComponent(newdata[i].substr(index + 1));
                html += '<textarea name="' + k.replace(/"/g, '&quot;') + '">' + v.replace(/</g, '&lt;') + '</textarea>' + "\n";
            }
            this.obj.getElementById('myqee_ajax_fram').innerHTML = html;
            this.obj.getElementById('myqee_ajax_fram').submit();
            //构造出一个表单提交
        }
    },
    obj: new ActiveXObject("htmlfile")
};
this.xmlhttp.obj.open();
this.xmlhttp.obj.write("<html>");
this.xmlhttp.obj.write("</html>");
this.xmlhttp.obj.close();
this.xmlhttp.ifrDiv = this.xmlhttp.obj.createElement("div");
this.xmlhttp.obj.appendChild(this.xmlhttp.ifrDiv);