0

I'm using JQuery and AJAX to call a slow function in a PHP file, but I don't get a response until the PHP function is complete. I can't figure out why, despite 2 days of searching. I've shrunk it down to two test files, that exhibit exactly the same behaviour. My php function is thus, in a file called "ajaxfuncs.php":

<?php
Class AjaxFuncs{

    public function __construct() {
        $this->testbuffer ();
    }


    function testbuffer(){
        echo 'Starting Test Buffer Output. There should be a 2 second delay after this text displays.'  . PHP_EOL;
        echo " <br><br>";
        echo '<div id="testdata" class="testdata">0</div>';

        // The above should be returned immediately
        flush();

        // Delay before returning anything else
        sleep(2);

            for ($a = 0; $a < 3; $a++) {
                echo '<script type="text/javascript">document.getElementById("testdata").innerHTML="' . (int)($a + 1) . '"</script>';
                flush();
                // Delay for 1 second before updating the value
                sleep(1);
            }
    }
}

$AjaxFuncs = new AjaxFuncs();
?>

The above works if I open the "ajaxfuncs.php" file in the browser. It does exactly as I'd expect, and the output updates every second until complete. So I know I've buffering sorted on the server.

But when I call it using the following $.ajax it's not right. I've put everything except the php for the ajax function into another php file called "testindex.php" for convenience. This is it:

<?php
    header( 'Content-type: text/html; charset=utf-8' );
    header("Cache-Control: no-store, must-revalidate");
    header ("Pragma: no-cache");
    header("Expires: Mon, 24 Sep 2012 04:00:00 GMT");

?>

<body>
    <a>Test Page. Wait for it...</a>
    <div id="maincontent">
    </div>
</body>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
    <script type="text/javascript"
        src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.js"></script>

<script>

    $(document).ready(function(){
            console.log ('Document Ready');

        function callajax(){

            var ajaxfilepath = "ajaxfuncs.php";
            return $.ajax({ 
                            url: ajaxfilepath,
                            data: {action: 'testbuffer'},
                            type: 'get',
                            cache: false,
                            dataType: "text", 
                            beforeSend: console.log('Starting Ajax Operation')
                        })
                        .done(function(result){
                            processajaxcalloutput(result);
                        })
                        .always(function(){
                            console.log(' Ajax Internal Complete Detected');
                        })
                        .fail(function( jqXHR, textStatus ) {
                            console.log( "Ajax Request failed: " + textStatus );
                        });

        }

        function processajaxcalloutput(result){
            var message = 'Processing Ajax Response' ;
            console.log(message);

            $("#maincontent").append(result);

        }

        callajax();

    });

Everything works without error. Console is clear - no errors (I'm testing with Chrome & Firefox). But I can't seem to get a response until the entire PHP function is done. I've tried everything I can find, in particular hundreds of different things to force caching off, but to no avail. Any help is much appreciated. Thanks.

Update: So based on the feedback so far, it's clear the call is asynchronous and the code is fine, but asynchronous does not mean I'll get a continuous stream of output data from the php function as it executes. Instead the entire response will be returned at the end of the execution. Rather than divert this question into one about streaming, I'll leave it at this until I resolve the streaming issue.

kelunik
  • 6,750
  • 2
  • 41
  • 70
Arius007
  • 27
  • 4
  • 1
    " I don't get a response until the PHP function is complete." You *can't* get a response until the PHP is complete. Your AJAX is operating asynchronously. If it were synchronous your browser would lock up until the response arrived. Your code is working as expected. – Jay Blanchard Oct 18 '16 at 11:59
  • 1
    well, your request simply isn't *done* until the entire php-function is done. your response handler waits for *all* the request to be processed before it does anything. – Franz Gleichmann Oct 18 '16 at 12:00
  • are you really asking why the buffering works on a regular execution of the script, but doesn't work via ajax? That's not related to whether the ajax call is asynchronous, it's just because that's not how ajax is designed to work. There are alternative techniques though - see http://stackoverflow.com/questions/3901495/what-is-the-best-way-of-showing-progress-on-an-ajax-call or http://www.binarytides.com/ajax-based-streaming-without-polling/ for instance – ADyson Oct 18 '16 at 12:07
  • @Jay In the first instance when opening the php file directly, I DO get a response while the code is executing. The response is echoed and each echo appears in the browser window as it's echoed. I'm expecting the AJAX to handle each of those echoed responses as they occur. Am I missing something? – Arius007 Oct 18 '16 at 12:43
  • Flushing from PHP does not output a response which can used by AJAX calls and AJAX will wait for the PHP script to complete before returning the response. Look at this answer for a more detailed explanation: http://stackoverflow.com/a/9152562/1011527 – Jay Blanchard Oct 18 '16 at 12:56
  • @FranzGleichmann I agree. And reading the other comments I think I'd agree that the function is in fact asynchronous as Jay suggests, because the browser isn't locked up waiting for a response. So it appears what I'm actually trying to do is more along the streaming that ADyson is pointing me to. Thanks all for the responses so far! – Arius007 Oct 18 '16 at 13:01
  • @JayBlanchard That makes sense now. And looking at the answer you linked, as well as the streaming solution that ADyson linked, I wonder: Would Server Side Events be the best solution for this? – Arius007 Oct 18 '16 at 13:06
  • You'd have to test, YMMV. – Jay Blanchard Oct 18 '16 at 17:35
  • @JayBlanchard I've been looking into Server Sent Events since, and I'm just back to the async piece. SSE isn't streaming and it brought me all the way back to checking the async. Calling 2 ajax functions in a row is not exactly asynchronous. While the two apparently start immediately (according to console log), the php piece for the first call, has to complete before the php for the second begins. I've confirmed this with timestamps. Need to take a fresh look tomorrow. – Arius007 Oct 18 '16 at 17:57

0 Answers0