写入div作为数据流

时间:2012-11-06 12:22:55

标签: php jquery ajax

考虑写入div的AJAX调用:

recent_req=$.post('result.php', { d: data }, function(returnData) {
    $('#content').html(returnData);
});

result.php处的PHP脚本执行一些需要花费时间的功能,每步约5-20秒。我正在使用PHP的flush()函数在每个步骤开始和结束时立即将信息提供给浏览器,但是如何让Javascript将数据写入#content div中?

感谢。

修改 澄清:假设result.php如下所示,由于约束不能实际重构:

<?php

echo "Starting...<br />";
flush();

longOperation();
echo "Done with first long operation.<br />";
flush();

anotherLongOperation();
echo "Done with another long operation.<br />";
flush();

?>

如何构建AJAX以调用result.php,以便在它们进入时将echo语句附加到#content div?有/无jQuery的任何解决方案都是受欢迎的。谢谢!

7 个答案:

答案 0 :(得分:5)

有一种技术可以使用iframe来实现这一目标。

与涉及框架的其他建议类似,但它不涉及会话或轮询或任何其他内容,并且不需要您显示iframe本身。它还具有在流程中的任何一点运行您想要的任何代码的好处,以防您使用UI进行更复杂的操作,而不仅仅是将文本推送到div(例如,您可以更新进度条)。

基本上,将表单提交给隐藏的iFrame,然后将javascript刷新到该帧,该帧与iFrame父级中的函数进行交互。

像这样:

<强> HTML:

<form target="results" action="result.php" method="post">
<!-- your form -->
<input type="submit" value="Go" />
</form>

<iframe name="results" id="results" width="0" height="0" />
<div id="progress"></div>

Javascript,在您的主页中:

function updateProgress(progress) {
  $("#progress").append("<div>" + progress + "</div>");
}

<强> result.php:

<?php

echo "<script language='javascript'>parent.updateProgress('Starting...');</script>";
flush();

longOperation();
echo "<script language='javascript'>parent.updateProgress('Done with first long operation.');</script>";
flush();

anotherLongOperation();
echo "<script language='javascript'>parent.updateProgress('Done with another long operation.');</script>";
flush();

?>

答案 1 :(得分:4)

您无法使用常规的ajax调用“流式传输”数据,因为您无法让用户的浏览器“监听”服务器请求。只有在数据处理完毕后才会调用“成功”功能。

但是,有很多关于互联网上'Ajax Push'的讨论,显然HTML5上有websocket对象,可用于让用户的浏览器监听服务器请求。语法定义还不是很稳定,所以你不想搞砸它,因为它可能很快就会改变。

您可能要做的是发送step1请求,等待其返回,然后发送step2请求。它会为你的整体处理时间增加一些开销(并且会使它更加冗长),但如果你只有几个重要的步骤它应该可以正常工作。如果您的步骤不需要太多处理,则不应该这样做(因为通信时间将大于您的“有效处理时间”)。

编辑:您还可以做的是例如在用户会话中写入进度。这样,您可以定期ping服务器并请求更新状态。这样,即使您有许多小步骤,您也只需每10秒左右发送一次请求,这是对每一步的调度的改进。

答案 2 :(得分:3)

作为替代解决方案,您可以向form提交隐藏的iframe,如以下示例所示:

<?php

function output_data($data)  {
    echo str_pad($data, 4096, ' ', STR_PAD_RIGHT) . "\n";
    flush(); 
}

function long_runner() {        
    output_data("");

    output_data(date("H:i:s").' - Starting...<br />');
    sleep(10);

    output_data(date("H:i:s").' - Done with first long operation.<br />');
    sleep(10);

    output_data(date("H:i:s").' - Done with another long operation.<br />');
    return("<script>parent.task_complete()</script>");
}

if (isset($_REQUEST["status"])) {
    die(long_runner());
}

?>
<!DOCTYPE html>
<html>
    <head>
        <title>Write to IFRAME as data streams in</title>
        <style>
        #myform { display: none }
        #frm { width: 50% }
        </style>
        <script language="javascript" type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
        <script>
        function task_complete() {
            alert('Task completed');
        }

        $(document).ready(function() { 
            $('#starter').click(function() {
                $('#myform').submit();
            });
        });
        </script>
    </head>
    <body>
        <form id="myform" method="get" target="frm" action="<?= $_SERVER['SCRIPT_NAME'] ?>">
            <input type="hidden" name="status" value="0">
        </form>
        <a href="#" id="starter">Start</a><br />
        <iframe id="frm" name="frm" frameborder="0"></iframe>
    </body>
</html>

答案 3 :(得分:3)

将动态数据流写入div:

这里......你具体询问如何动态地将数据流写入“div”。正如许多人所说,可以动态地写入iframe,我们只需要更进一步。以下是您的问题的完整解决方案,它将把数据带回您的div,最大延迟为.5秒。如果您需要更快速的更新,可以对其进行调整。

<!DOCTYPE html>
<html>
<head>
    <title>dynamic listener</title>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
    <script type="text/javascript">
    var count;
    $(function(){
        $('#formx').submit(function(){
            setTimeout(function(){ check_div(); }, 500);
            count = 0;
            return true;
        });
    });

    function check_div()
    {
        var $iframetxt = $('#iframex').contents().text();
        var $div = $('#dynamic');
        if( $iframetxt != $div.text() )
        {
            console.log('rewritten!');
            $div.text( $iframetxt );
            setTimeout(function(){ check_div(); }, 500);
            count = 0;
        }
        else
        {
            count++;
            if(count < 40) setTimeout(function(){ check_div(); }, 500);
            else console.log('timed out');
        }       
    }
    </script>
</head>
<body>
    <div>
        Form
        <form id="formx" action="result.php" method="post" target="iframex">
            <input type="submit" />
        </form>
    </div>
    <div id="dynamic"></div>
    <iframe id='iframex' name="iframex" style="display:none" ></iframe>
</body>
</html>

<强> 1。在表单提交时,流数据将发送到iframe。

为此,我们只需将表单标记中的target属性设置为iframe名称。

<强> 2。 check_div()每隔0.5秒运行一次,以将#dynamic div的文本与iframe的文本内容进行比较。

如果它们之间存在差异,则会将数据写入div并再次调用超时。如果没有差异,则超时计数器递增。如果计数小于40(40 x .5秒= 20秒),则再次调用超时。如果没有,我们假设流已经完成。

答案 4 :(得分:2)

以下是使用会话进行轮询的解决方案:

HTML:

<!DOCTYPE html>
<html>
<body>
    <div id="content"></div>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
    <script>
    var pollTimeout;
    function pollResult(){
        $.get('poll.php', function(response) {
            // Update #content with partial response
            $('#content').html(response);
            pollTimeout = setTimeout(pollResult, 1000);
        });
    }
    $.post('result.php', function(response) {
        // Result is loaded, stop polling and update content with final response
        clearTimeout(pollTimeout);
        $('#content').html(response);
    });
    // Start polling
    pollResult();
    </script>
</body>

</html>

结果PHP:

<?php

class SemiStream{

    public function __construct(){
        @session_start();
        $_SESSION['semi_stream'] = '';
    }

    public function write($data){
        @session_start();
        $_SESSION['semi_stream'] .= $data;
        // We have to save and close the session to be
        // able to read the contents of it in poll.php
        session_write_close();
    }

    public function close(){
        echo $_SESSION['semi_stream'];
        unset($_SESSION['semi_stream']);
    }
}

$stream = new SemiStream();
$stream->write("Starting...<br />");

sleep(3);

$stream->write("Done with first long operation.<br />");

sleep(3);

$stream->write("Done with another long operation.<br />");
$stream->close();

echo 'Done.';

轮询PHP:

<?php
session_start();
echo $_SESSION['semi_stream'];

这没有使用PHP的输出缓冲。

答案 5 :(得分:0)

查看推送服务,看起来它可以完全符合您的要求:http://pusher.com/

答案 6 :(得分:0)

问题可能是如何在您的应用中实施Push技术。我建议你看 this question which has great answer with example