jquery ajax调用不是异步的

Pat*_*ick 3 php jquery asynchronous race-condition

我对jQuery实现它的AJAX方法很新鲜.

我有一个简单的设置,访问两个不同的页面,一个需要10秒钟完成(我有一个计时器设置)和一个检查第一页的状态.

这两个函数progressCheck()每秒都以最新状态请求其页面,beginLogin()并且需要10秒才能加载.我在服务器上的用户对象中设置了一个值,两个页面都通过symfony 1.4访问.

问题是,在progressCheck()我点击之前正常工作beginLogin(),然后在完成之前不会进行任何更改beginLogin().我有两个函数设置为异步运行.我知道这一定很简单,但是我很茫然.

我在运行此页面时运行了Firebug-Net,结果是: AJAX网络电话

许多的progressCheck()等待期间为10秒的电话叫,但净说,他们跑了进来〜200毫秒,没有任何等待时间.

有任何想法吗?

代码如下:

<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>
Run Code Online (Sandbox Code Playgroud)

更新 以下是两个PHP函数,它们返回两个页面调用的数据

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



}
Run Code Online (Sandbox Code Playgroud)

Pat*_*ick 7

我发现了javascript调用挂起的原因.

为了防止用户会话数据发生竞争条件,PHP会锁定数据,直到出现两种情况之一.

  1. 以前称为PHP脚本调用session_write_close().

  2. 以前调用的PHP脚本完成处理并隐式调用session_write_close().

遵循对不调用的服务器的调用session_start()应该允许真正的异步调用的逻辑,我创建了一个虚拟PHP页面,它只是吐出一个简单的字符串,并在10秒脚本运行时每秒调用该页面.它跑得很好.

该解决方案来自阅读这个讨论上symfony的论坛.