9

情况:
我正在使用 $.ajax() POST 向 php 脚本发送请求,该脚本将大约 400,000-500,000 行插入到数据库中。这始终需要大约 3.5 - 4 分钟。(在此期间,请求处于待处理状态)。

问题:
我需要一些方法来显示页面上的进度。(比如一个 %)。我尝试在每 5 秒左右检查一次的 setInterval 中使用 $.ajax() ,但它们似乎会在第一个(更长的) $.ajax() 完成时建立起来并且全部通过。

问题:
默认情况下 $.ajax() 不是异步的吗?这不应该意味着可以在任何时间以任何顺序发送请求,并且应该在任何时间以任何顺序接收响应吗?这甚至与异步有关吗?有没有办法从一个请求中定期发回“半响应”?或者我不能在有待处理的请求/响应时发送和接收请求/响应?(见下图)

提前致谢!!!

多个请求 http://kshaneb.com/reqres.png

4

4 回答 4

8

您长时间运行的 ajax 调用可能会在服务器上打开一个会话,因此由于会话文件锁定,所有下一个请求都会被阻止。

问题: 默认情况下,PHP 将其会话数据写入文件。当对启动会话 (session_start()) 的 PHP 脚本发出请求时,该会话文件被锁定。这意味着如果您的网页向 PHP 脚本发出大量请求,例如,通过 Ajax 加载内容,则每个请求都可能锁定会话并阻止其他请求完成。其他请求将在 session_start() 上挂起,直到会话文件被解锁。如果您的 Ajax 请求之一运行时间相对较长,这尤其糟糕。

解决方案: 会话文件保持锁定状态,直到脚本完成或手动关闭会话。为了防止多个 PHP 请求(需要 $_SESSION 数据)阻塞,您可以启动会话,然后关闭会话。这将解锁会话文件并允许剩余请求继续运行,即使在初始请求完成之前也是如此。

更多信息在这里: http: //konrness.com/php5/how-to-prevent-blocking-php-requests/

于 2013-06-21T06:35:52.280 回答
2

希望这可以帮助

$(function ()
    {
        var statusElement = $("#status");

        // this function will run each 1000 ms until stopped with clearInterval()
        var i = setInterval(function ()
        {
            $.ajax(
            {
                success: function (json)
                {
                    // progress from 1-100
                    statusElement.text(json.progress + "%");

                    // when the worker process is done (reached 100%), stop execution
                    if (json.progress == 100) clearInterval(i);
                },

                error: function ()
                {
                    // on error, stop execution
                    clearInterval(i);
                }
            });
        }, 1000);
    });
于 2013-06-21T06:22:12.870 回答
1

Instead of doing an ajax post you can post to an iframe and have php generate incremental output and send it with the flush command.

 // send a hash mark for every 1000 inserts
 $a = 0;
 while ($rec = getDataForNextInsert()){
       $a++;
       // do insert
       if ($a%1000 == 0) { echo '#'; flush(); }
 }

It would also then be possible to poll the contents of the iframe to provide a pretty display for the end user.

于 2013-06-21T06:15:49.003 回答
1

我希望这对你有用

首先,您需要在 PHP 脚本中禁用输出缓冲区

@apache_setenv('no-gzip', 1);
@ini_set('zlib.output_compression', 0);
@ini_set('implicit_flush', 1);
for ($i = 0; $i < ob_get_level(); $i++) { ob_end_flush(); }
ob_implicit_flush(1);

然后您需要在此过程中从 PHP 中回显您的进度,如下所示:

for($i=0;$i < 20;$i++){
    echo ($i > 0 ? "#":"").($i/20*100);
    sleep(1);
}

然后,在 javascript 中,您需要侦听 xhr readystate 更改事件,当发生这种情况时,只需解析响应文本并根据需要显示进度。

监听事件:

$.ajaxPrefilter(function( options, _, jqXHR ) {
                if ( options.onreadystatechange ) {
                    var xhrFactory = options.xhr;
                    options.xhr = function() {
                        var xhr = xhrFactory.apply( this, arguments );
                        function handler() {
                            options.onreadystatechange( xhr, jqXHR );
                        }
                        if ( xhr.addEventListener ) {
                            xhr.addEventListener( "readystatechange", handler, false );
                        } else {
                            setTimeout( function() {
                                var internal = xhr.onreadystatechange;
                                if ( internal ) {
                                    xhr.onreadystatechange = function() {
                                        handler();
                                        internal.apply( this, arguments ); 
                                    };
                                }
                            }, 0 );
                        }
                        return xhr;
                    };
                }
            });

和ajax请求示例:

$.ajax({
                    url: "test.php",
                    cache: false,
                    onreadystatechange: function( xhr ) {
                        res = xhr.responseText.split("#");
                        $("#id").html(res[res.length-1] + "% done<br/>");
                    }                   
                }).done(function( data ) {
                        $("#id").append("all done!</br>");
                    }); 
            });

使用 jQuery 1.5+ 测试

于 2013-06-21T09:17:37.013 回答