Andrei Herford
Andrei Herford

Reputation: 18765

Why are jQuery AJAX request to Symfony Controllers are handled in parallel instead of async?

When posting simple data to a plain PHP script using jQuery $.ajax({...}) multiple requests are handled in parallel. When doing to same with a Symfony 2.8 controller as a target, the request is handled synchronously. Why is this?

Plain HTML and PHP setup

// Plain PHP file: /testscript.php
<?php 
    sleep($_POST['time']);
    echo $_POST['id'];


// Plain HTML file: /testpage.html
<html>
<head>
    <script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
</head>
<body>
Click here:
<div id='testbtn' style="background-color: #abc">Click</div>

 <script>
    $(document).ready(function() {
        var start = new Date().getTime();
        var count = 1;

        $("#testbtn").click(function() {
            var time = new Date().getTime();
            console.log('Click at '+count+':' + (time - start));

            $.ajax({
                url : '/testscript.php',
                type : "post",
                data : {'time':3, 'id':count},
                async: true,
                context : this,
                success : function(data) {
                    var end = new Date().getTime();
                    console.log('Click Success: ' + data + "  -  " + (end - start));
                }
            });

            count++;
        });


        $.ajax({
            url : '/testscript.php',
            type : "post",
            data : {'time':10, 'id':0},
            async: true,
            context : this,
            success : function(data) {
                var end = new Date().getTime();
                console.log('Auto Success: ' + data + "  -  " + (end - start));
            }
        });

        console.log('Ajax fired');
    });
</script>

</body>
</html>    

Symfony Setup

// Controller Action to handle /sym_testscript.php
public function testScriptAction(Request $request) {
    sleep($request->get('time'));
    return new Response($request->get('id'), Response::HTTP_OK);
}


// Controller Action to handle /sym_testpage.php
public function testPageAction() {
    return $this->render('MyBundle::sym_testpage.html.twig');
}   


// Twig-Template for /sym_testpage.html
...exactly the same HTML code as above. Twig is only used to insert URL
...
$.ajax({
    url : '{{ path('sym_testscript') }}',
    ...

The page /testpage.html calls /testscript.php when being loaded with a sleep-value of 10 seconds. When clicking the Button a few times the page load waterfall looks something like this:

1: ========================================   // initial call of testscript.php
2:     ============                           // testscript.php called by 1 click
3:      ============                          // testscript.php called by 2 click
4:         ============                       // testscript.php called by 3 click

Each click on the Button immediately calls the testscript.php which is then executed in parallel to the initial call and other button calls. So each click-call runs 3 seconds.

When using the Symfony version instead, the waterfall looks like this:

1: ========================================   // initial call of testscript.php
2:     ====================================================                           
3:      ================================================================                          
4:         ============================================================================

Again, each button click immediately calls the /sym_testscript.php. But now the calls are handled one after the other. Thus the total runtime is not 10 seconds but 19 = 10 + 3 + 3 + 3...

When using the sym_testscript.php within the plain HTML file as the target, the result is the same. Thus the problem seems to be within the Symfony controller...

Why is this? Why are the ajax-calls not handled in parallel when using the Symfony solution?

Upvotes: 4

Views: 716

Answers (1)

jeroen
jeroen

Reputation: 91762

As soon as you start a session in php, php will lock it and subsequent requests will have to wait until the session is available again.

So if your symfony script uses sessions, you can only execute 1 request at a time using that session while the session is open.

Disabling sessions (if that even is an option...) or closing it when you don't need it any more will allow parallel requests.

Upvotes: 4

Related Questions