3

I am fresh to jQuery's implementation of it's AJAX methods.

I have a simple setup that accesses two different pages, one which takes 10 seconds to complete (I have a timer set on it) and one which checks on the status of the first page.

The two functions are progressCheck() which requests its page every second with the latest status and beginLogin() which takes 10 seconds to load. I set a value in the user object on the server that both pages access through symfony 1.4.

The issue is that the progressCheck() works correctly until I click beginLogin(), then no changes are made until beginLogin() finishes. I have both functions setup to run asynchronously. I know it must be something simple to figure out, but I am at a loss.

I ran Firebug - Net while running this page and the result is: AJAX Net calls

A number of the progressCheck() are called during the wait period for the 10 second call, but Net says they ran in ~200 ms without any wait time.

Any ideas?

Code below:

<button onclick="beginLogin();">Begin Login</button> 
<button onclick="progressCheck();">Check Progress</button> 
<button onclick="clearCheck();">Clear Check</button>
<br/>
<div id="result_div">

</div>
<div id="progress_div">

</div>

<style type="text/css">
    #progress_div
    {
        width:              800px;
        height:             200px;
        border:             1px solid #CCCCCC;
        overflow:           scroll;
        background-color:   #AAEEFF;
    }

    #result_div
    {
        width:              800px;
        height:             300px;
        border:             1px solid #CCCCCC;
        overflow:           scroll;
        background-color:   #FFEEAA;
    }
</style>
<script type="text/javascript">
    function beginLogin()
    {
        try
        {
            var login_url   = "http://example.com/home/loginScript";
            $.ajax({
                url:        login_url,
                success:    function(data){
                    $("#result_div").append('<pre>'+data+'</pre><hr/>');
                    alert("finished");
                }
            });
        }
        catch(e)
        {
            alert("There was an error beginning the login: " + e);
            return false;
        }
        return true;
    }

    function progressCheck()
    {
        try
        {
            var check_url   = "http://example.com/home/checkLoginProgress";
            $.ajax({
                url:        check_url,
                success:    function(data){
                    $("#progress_div").append('<pre>'+data+'</pre><hr/>');
                }
            });
        }
        catch(e)
        {
            alert("There was an error checking the progress: " + e);
            return false;
        }
        check_id = setTimeout('progressCheck()', 1000);
        return true;
    }

    // set progress checking function to call every second
    var check_id = setTimeout('progressCheck()', 1000);

    function clearCheck()
    {
        try
        {
            clearTimeout(check_id);
        }
        catch(e)
        {
            alert("There was an error clearing the check: " + e);
            return false;
        }
        return true;
    }
</script>

UPDATE Here are the two PHP functions that returns the data for the two page calls

define('DEBUG', true);

public function executeCheckLoginProgress(sfWebRequest $request)
{
    if($this->getUser()->hasAttribute('login_script', 'sfGuardSecurityUser'))
        $this->login_progress = $this->getUser()->getAttribute('login_script', -1, 'sfGuardSecurityUser');
    else
        $this->login_progress = '[undefined]';
    $conn = $this->connectTestDb();
    $query  = sprintf("SELECT * FROM company_type WHERE id = 1;");
    $result = mysql_query($query, $conn);
    $this->login_progress = mysql_result($result, 0, 'name');
    if($request->isXmlHttpRequest())
    {   // this is an ajax all, only return value
        $this->getResponse()->setHttpHeader("Content-type", "text/plain");
        $this->getResponse()->setContent($this->login_progress);
        return sfView::NONE;
    }
}

public function executeLoginScript(sfWebRequest $request)
{
    $user = $this->getUser();
    if(!$user->hasAttribute('login_script', 'sfGuardSecurityUser'))
        $user->setAttribute('login_script', 0, 'sfGuardSecurityUser');

    $this->login_value      = $user->getAttribute('login_script', 0, 'sfGuardSecurityUser');

    $conn = $this->connectTestDb();
    $query  = sprintf("SELECT * FROM company_type WHERE id = 1;");
    $result = mysql_query($query, $conn);
    $this->login_value = mysql_result($result, 0, 'name');

    $result = $user->assignAccessLevelIds();
    if($result === true)
    {
        $this->login_value += 5;
        $user->setAttribute('login_script', $this->login_value, 'sfGuardSecurityUser');
        $query  = sprintf("UPDATE company_type SET `name` = '%s' WHERE id = 1;", mysql_real_escape_string($this->login_value));
        $result = mysql_query($query, $conn);
        $this->login_progress = mysql_result($result, 0, 'name');
    }
    else
    {
        DataMan::logRawMessage('Unable to set access level user ['.$user->getAttribute('user_id', null, 'sfGuardSecurityUser'), sfLogger::WARNING);
    }
    // just for testing sleep!
    if(DEBUG === true)
        sleep(5);

    $result = $user->assignCompanyIds();
    if($result === true)
    {
        $this->login_value += 5;
        $user->setAttribute('login_script', $this->login_value, 'sfGuardSecurityUser');
        $query  = sprintf("UPDATE company_type SET `name` = '%s' WHERE id = 1;", mysql_real_escape_string($this->login_value));
        $result = mysql_query($query, $conn);
        $this->login_progress = mysql_result($result, 0, 'name');
    }
    else 
    {
        DataMan::logRawMessage('Unable to set company ids user ['.$user->getAttribute('user_id', null, 'sfGuardSecurityUser').'] '.__LINE__, sfLogger::WARNING);
    }
    // just for testing sleep!
    if(DEBUG === true)
        sleep(5);



}
4
  • 3
    Check the shared user object that you set on server side, it might get locked when beginLogin() accesses it, so the next request for progresscheck() is waiting for that lock to release on server side. Commented Feb 23, 2011 at 4:59
  • is your server-side code hosted online? Commented Feb 23, 2011 at 5:15
  • @Furqan the user object is only accessible to that specific user, so I set the functions to save to the database and opened up the same page in two browsers. the browser that I clicked beginLogin() hung for the 10 seconds while the second browser that was just running progressCheck() updated at the correct times with the new values. Commented Feb 23, 2011 at 5:54
  • @Anurag i'll update the question with the PHP code for the two pages Commented Feb 23, 2011 at 5:55

2 Answers 2

7

I have discovered the cause of the javascript call hanging.

To prevent a race condition from occurring with user session data, PHP locks the data until one of two conditions occur.

  1. The previously called PHP script calls session_write_close().

  2. The previously called PHP script completes processing and implicitly calls session_write_close().

Following the logic that a call to the server that does not call session_start() should allow true asynchronous calls, I created a dummy PHP page that just spits out a simple string and called to that page every second while the 10 second script ran. It ran perfectly.

The solution came from reading this discussion on the symfony forums.

Sign up to request clarification or add additional context in comments.

1 Comment

I am facing the same issues, How to integrate this solution with codeingniter action?
0

What about something like

I dropped the try catch's and made your setTimeout's to look like check_id = setTimeout(progressCheck, 1000);

function beginLogin(){
    var login_url = "http://example.com/home/loginScript";
    return $.ajax({
        url: login_url,
        success: function(data){
            $("#result_div").append('<pre>' + data + '</pre><hr/>');
            alert("finished");
        },
        error: function(a, b, c){
            console.log(a)
            console.log(b)
            console.log(c)
        }
    });
}

function progressCheck(){
    var check_url = "http://example.com/home/checkLoginProgress";
    var ajax = $.ajax({
        url: check_url,
        success: function(data){
            $("#progress_div").append('<pre>' + data + '</pre><hr/>');
        },
        error: function(a, b, c){
            console.log(a)
            console.log(b)
            console.log(c)
        }
    });

    check_id = setTimeout(progressCheck, 1000);
    return ajax;
}

// set progress checking function to call every second
var check_id = setTimeout(progressCheck, 1000);

function clearCheck(){
    try {
        clearTimeout(check_id);
    } catch (e) {
        alert("There was an error clearing the check: " + e);
        return false;
    }
    return true;
}

1 Comment

i plugged that into my code and it still hangs until the 10 second script finishes, then I get a whole rush of all the progressCheck()s that were called in the 10 seconds

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.