我正在研究使用 ajax 请求和 session 变量更新进度的进度条。当我的程序执行耗时的操作(例如发送许多电子邮件等)时,它只是设置适当的 session 变量(其中包含进度值)。此操作由以下代码中的函数 post() 启动。
与此同时,第二个函数 ask() 每 500 毫秒循环执行一次。它应该实时返回当前进度。这就是问题所在:ask() 发送的每个请求都在等待 post() 函数发送的请求完成。有趣的是,如果我设置一些 URL,比如 google.com 而不是 url/to/progress,它就可以正常工作,只是它不是我想要的 :)。这意味着问题出在服务器端。
不确定它是否重要,但我使用 Yii 框架。
下面的所有代码都只是草稿(但有效),其唯一目的是展示我的意思。
提前致谢。
抱歉我的英语不好:)
查看部分:
<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>
Controller 部分:
public function actionPost($time) {
sleep(5); // time consuming operation
echo $time . ' : ' . microtime();
exit;
}
public function actionProgress($time) {
echo $time . ' : ' . microtime();
exit;
}
最佳答案
我认为您的问题与 session 相关。
当脚本有一个打开的 session 时,它会锁定 session 文件。这意味着任何使用相同 session ID 的后续请求都将排队,直到第一个脚本释放它对 session 文件的锁定。您可以使用 session_write_close()
强制执行此操作- 但这并不能真正帮助你,因为你正试图与 session 文件共享进度信息所以 post
脚本需要保持 session 数据打开和可写。
您需要想出另一种在 post
之间共享数据的方式。和 progress
脚本 - 如果 post
在整个执行过程中打开 session 数据,progress
在 post
之前将永远无法访问 session 数据执行完毕。也许您可以使用 session ID 创建一个临时文件 post
具有写入权限,您可以在其中放置进度指示器数据。 progress
可以检查文件并返回该数据。 IPC(进程间通信)有很多选项 - 这不是一个特别漂亮的选项,但它确实具有最大可移植性的优势。
作为旁注 - 请不要将字符串传递给 setInterval()
, 传递函数。所以你的行实际上应该是:
var progress = setInterval(ask, 500);
但是 - 使用 setTimeout()
会更好在success
/error
ask()
的处理程序 Ajax 功能。这是因为通过使用 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>
...尽管这仍然不能解决 session 问题。
关于php - PHP 和 Ajax 的进度条,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9311986/