我试图弄清楚是否有机会通过多个(时间间隔的)ajax 调用接收任务的完成状态(通过 ajax 调用触发)。 基本上,在执行可能需要很长时间的事情期间,我想填充一些变量并在询问时返回它的值。
服务器代码如下所示:
function setTask($total,$current){
$this->task['total'] = $total;
$this->task['current'] = $current;
}
function setEmptyTask(){
$this->task = [];
}
function getTaskPercentage(){
return ($this->task['current'] * 100) / $this->task['total'];
}
function actionGetTask(){
if (Yii::$app->request->isAjax) {
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
return [
'percentage' => $this->getTaskPercentage(),
];
}
}
假设我处于 for 循环中,并且我知道迭代了多少次:
function actionExportAll(){
$size = sizeof($array);
$c = 0;
foreach($array as $a){
// do something that takes relatively long
$this->setTask($size,$c++);
}
}
在客户端我有这个:
function exportAll(){
var intervalId = setInterval(function(){
$.ajax({
url: '/get-task',
type: 'post',
success: function(data){
console.log(data);
}
});
},3000);
$.ajax({
url: '/export-all',
type: 'post',
success: function(data){
clearInterval(intervalId); // cancel setInterval
// ..
}
});
}
这看起来可行,除了 setInterval 函数中完成的 ajax 调用在“export-all”完成并进入成功回调之后完成这一事实。 在这个逻辑中我肯定缺少一些东西。 谢谢
最佳答案
问题可能出在 session 中。
让我们看看发生了什么。
- 对
/export-all
的请求由浏览器发送。 - 服务器上的应用调用
session_start()
打开 session 文件并锁定对其的访问。 - 应用开始执行昂贵的操作。
- 在浏览器中,设置的时间间隔过去后,浏览器将请求发送到
/get-task
。 - 服务器上的应用尝试处理
/get-task
请求并调用session_start()
。它被阻止,必须等待/export-all
请求完成。 /export-all
的昂贵操作已完成,响应已发送到浏览器。- session 文件已解锁,
/get-task
请求最终可以继续通过session_start()
。同时浏览器已收到/export-all
响应并为其执行成功回调。 /get-task
请求已完成,响应已发送到浏览器。- 浏览器收到
/get-task
响应并执行其成功回调。
处理它的最佳方法是避免直接从用户浏览器执行的请求运行昂贵的任务。
您的 export-all
操作应该只计划执行任务。然后任务本身可以由某些 cron 操作或后台的某些工作人员执行。 /get-task
可以检查其进度并在任务完成时触发最终操作。
您应该看看yiisoft/yii2-queue
扩大。此扩展允许您创建作业
,将它们排入队列,并通过 cron 任务或运行一个监听任务并在任务到来时执行它们的守护进程来运行队列中的作业。
关于javascript - Ajax 调用 DURING 另一个 Ajax 调用来接收服务器的任务计算状态并将其作为进度条显示给客户端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59305943/