paw*_*elo 6 php jquery post progress request
我正在使用进度条,使用ajax请求和会话变量更新进度.当我的程序执行耗时的操作,如发送许多电子邮件等时,它只是设置适当的会话变量(包含进度值).此操作由下面的代码中的函数post()启动.
同时,第二个函数ask()每500ms循环执行一次.它应该实时返回当前进度.这就是问题:ask()发送的每个请求都在等待post()函数发送的请求完成.有趣的是,如果我设置一些像google.com这样的URL而不是url/to/progress它可以正常工作,除非它不是我想要的:).这意味着问题出在服务器端.
不确定它是否重要,但我使用的是Yii Framework.
下面的所有代码只是划痕(但有效),其唯一目的是展示我的意思.
提前致谢.
抱歉我的英语不好:)
查看部分:
<script type="text/javascript">
function ask() {
var d = new Date();
var time = d.getTime();
$.ajax({
type: 'get',
url: '/url/to/progress' + '?time=' + time,
success: function(data) {
$("#progress").html(data);
}
})
}
function post() {
var d = new Date();
var time = d.getTime();
$.ajax({
type: 'post',
url: '/url/to/post' + '?time=' + time,
data: {"some": "data"},
success: function(data) {alert(data)}
});
}
$("#test").click(
function() {
post();
var progress = setInterval("ask();", 500);
}
);
</script>
Run Code Online (Sandbox Code Playgroud)
控制器部分:
public function actionPost($time) {
sleep(5); // time consuming operation
echo $time . ' : ' . microtime();
exit;
}
public function actionProgress($time) {
echo $time . ' : ' . microtime();
exit;
}
Run Code Online (Sandbox Code Playgroud)
我认为你的问题与会话有关.
当脚本具有打开的会话时,它会锁定会话文件.这意味着任何使用相同会话ID的后续请求都将排队,直到第一个脚本释放它对会话文件的锁定为止.您可以强制执行此操作session_write_close()
- 但这不会对您有所帮助,因为您尝试与会话文件共享进度信息,因此post
脚本需要保持会话数据的开放性和可写性.
您需要提出另一种在脚本post
和progress
脚本之间共享数据的方法- 如果post
会话数据在执行过程中打开,则在执行完毕progress
之前永远无法访问会话数据post
.也许您可以使用会话ID创建一个临时文件,该文件post
具有写入权限,您可以在其中放置进度指示器数据.该progress
可检查文件并返回数据.IPC(进程间通信)有很多选择 - 这不是一个特别漂亮的选项,但它确实具有最大的可移植性.
作为旁注 - 请不要传递字符串setInterval()
,传递函数.所以你的行实际上应该是:
var progress = setInterval(ask, 500);
Run Code Online (Sandbox Code Playgroud)
但是 - 最好在ajax函数setTimeout()
的success
/ error
handlers中使用ask()
.这是因为通过使用setInterval()
,无论前一个请求的状态如何,都将启动新请求.在开始下一个请求之前等待上一个请求完成会更有效.所以我会做更像这样的事情:
<script type="text/javascript">
// We'll set this to true when the initail POST request is complete, so we
// can easily know when to stop polling the server for progress updates
var postComplete = false;
var ask = function() {
var time = new Date().getTime();
$.ajax({
type: 'get',
url: '/url/to/progress' + '?time=' + time,
success: function(data) {
$("#progress").html(data);
if (!postComplete)
setTimeout(ask, 500);
}
},
error: function() {
// We need an error handler as well, to ensure another attempt gets scheduled
if (!postComplete)
setTimeout(ask, 500);
}
}
});
}
$("#test").click(function() {
// Since you only ever call post() once, you don't need a seperate function.
// You can just put all the post() code here.
var time = new Date().getTime();
$.ajax({
type: 'post',
url: '/url/to/post' + '?time=' + time,
data: {
"some": "data"
},
success: function(data) {
postComplete = true;
alert(data);
}
error: function() {
postComplete = true;
}
});
if (!postComplete)
setTimeout(ask, 500);
}
});
</script>
Run Code Online (Sandbox Code Playgroud)
...虽然这仍然无法解决会话问题.
上面的@DaveRandom正确地指出你是会话存储锁的受害者.
解决方法非常简单.您希望使进程的脚本post()
释放对会话数据的锁定,以便处理的脚本ask()
可以访问此会话数据.你可以这样做session_write_close
.
这里的细则是,在调用之后,session_write_close
您将无法访问会话变量,因此您需要相应地构造脚本post
:
$_SESSION
并保存其副本.session_write_close
以释放会话锁定.$_SESSION
直接获取.或者,您可以在脚本的生命周期内多次切换会话锁定:
session_start();
$_SESSION['name'] = 'Jon';
// Quick operation that requires session data
echo 'Hello '.$_SESSION['name'];
// Release session lock
session_write_close();
// Long operation that does not require session data.
sleep(10);
// Need access to session again
session_start();
echo 'Hello again '.$_SESSION['name'];
Run Code Online (Sandbox Code Playgroud)
这种安排使得当它睡眠的脚本时,其他脚本可以毫无问题地访问会话数据.