jquery ajax调用不是异步的
我对 jQuery 的 AJAX 方法的实现很陌生。
我有一个简单的设置,可以访问两个不同的页面,一个需要 10 秒才能完成(我在上面设置了一个计时器),另一个检查第一页的状态。
这两个函数是 progressCheck()
每秒请求其页面提供最新状态,以及 beginLogin()
需要 10 秒加载。我在服务器上的用户对象中设置了一个值,两个页面都通过 symfony 1.4 访问该值。
问题是 progressCheck()
正常工作,直到我单击 beginLogin()
,然后在 beginLogin()
完成之前不会进行任何更改。我将这两个函数设置为异步运行。我知道这一定很简单,但我很茫然。
我在运行此页面时运行 Firebug - Net,结果是:
在 10 个等待期间,会调用许多 progressCheck()
第二次调用,但 Net 表示他们在大约 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>
更新 下面是两个 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);
}
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:
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);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我发现了 javascript 调用挂起的原因。
为了防止用户会话数据出现竞争条件,PHP 会锁定数据,直到出现以下两个条件之一发生。
先前调用的 PHP 脚本调用
session_write_close()
。之前调用的 PHP 脚本完成处理并隐式调用
session_write_close()
。按照对不调用
session_start()
的服务器的调用应允许真正的异步调用的逻辑,我创建了一个虚拟 PHP 页面,该页面仅输出一个简单的字符串,并每秒调用该页面10 秒脚本运行。它运行得很完美。该解决方案来自阅读 symfony 论坛上的讨论。
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.
The previously called PHP script calls
session_write_close()
.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.
怎么样?
像我放弃了 try catch 并让你的 setTimeout 看起来像
check_id = setTimeout(progressCheck, 1000);
What about something like
I dropped the try catch's and made your setTimeout's to look like
check_id = setTimeout(progressCheck, 1000);