Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Write to div as data streams in

Tags:

jquery

ajax

php

Consider an AJAX call that writes to a div:

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

The PHP script at result.php performs some functions that take time, about 5-20 seconds per step. I am using PHP's flush() function to get the info to the browser as soon as each step starts and ends, but how can I get the Javascript to write the data to the #content div as it comes in?

Thanks.

EDIT: To clarify: Assume result.php looks like the following and due to constraints cannot be practically refactored:

<?php

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

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

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

?>

How might the AJAX be structured to call result.php such that the echo statements are appended to the #content div as they come in? Any solution with / without jQuery is welcome. Thanks!

like image 801
dotancohen Avatar asked Nov 06 '12 12:11

dotancohen


2 Answers

There's a technique using an iframe which you could use to achieve this.

Similar to other suggestions involving frames but it doesn't involve sessions or polling or anything, and doesn't need you to display the iframe itself. It also has the benefit of running any code you want at any point in the process, in case you're doing something more sophisticated with your UI than just pushing text to a div (e.g. you could update a progress bar).

Basically, submit the form to a hidden iFrame then flush javascript to that frame, which interacts with functions in the iFrame's parent.

Like this:

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, in your main page:

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();

?>
like image 123
Jed Watson Avatar answered Oct 14 '22 14:10

Jed Watson


You cannot 'stream' data using regular ajax calls, for you can't make your user's browser 'listen' to server requests. Your 'success' function will only be called when data's done processing.

There's, though, much discussion on 'Ajax Push' on the internet and apparently HTML5 has websocket objects that can be used to make your user's browser listen to server requests. The syntax definition is not quite stable yet, so you don't want to mess with it, as it may change soon.

What you may want to do is dispatch a request for step1, wait for its return and then dispatch a request for step2. It'll add some overhead to your overall processing time (and will make it much more verbose), but it should work fine if you only have a few big steps. If your steps don't take too much processing, you shouldn't do it (as the communication time will become greater than your 'effective processing time').

EDIT: What you can also do is write the progress on the user's session, for example. That way, you can periodically ping the server with a request for an update on the status. This way, even if you have many small steps, you'll only have to dispatch requests every 10 seconds or so, that being an improvement over dispatching for every step.

like image 4
Pedro Cordeiro Avatar answered Oct 14 '22 13:10

Pedro Cordeiro