CodeIgniter实时进度条Ajax阻塞问题求解
问题
我正尝试实现实时显示长进程进度的进度条,大部分功能已完成,但遇到了棘手问题:
点击按钮后触发的JavaScript函数会做两件事:
- 发起异步Ajax调用启动长运行脚本,该脚本会在关键节点更新数据库中的进度值(0-100)。
- 通过定时器发起同步调用,读取数据库进度来更新UI进度条。
但实际运行时,操作(2)会等待操作(1)完成才执行。开发者工具显示请求已发送,但推测CodeIgniter会把第二个Ajax请求排队,直到第一个请求结束。
想知道怎么让操作(2)在操作(1)执行期间多次获取进度?
相关代码
按钮点击触发函数:
function button_pressed_for_long_action(type, id) { // 启动定时器 timer = window.setInterval(get_progress, 3000); // 调用长运行脚本 $.ajax({ url: "/the URL for long action/", dataType: "json", method: "POST", data: { type : type, id : id }, success:function(data) { }, error: function( data, status, error ) { alert("error"); alert(error); } }); }
定时器调用的进度获取函数:
function get_progress() { $.ajax({ url: "/url to get process/", dataType: "json", method: "POST", async : false, data: { some_id : some_id }, success:function(data) { // 更新UI if (progress < 100) { // 未完成则退出 return; } // 脚本完成,清除定时器 window.clearInterval(timer); }, error: function( data, status, error ) { alert("error"); alert(error); } }); }
这些URL对应的CodeIgniter控制器函数能正常读写数据库并返回JSON,问题仅在于进度请求需等待长脚本请求完成。
解决方案
问题根源
- 同步请求阻塞:
get_progress里的Ajax设置了async: false,这会让浏览器阻塞主线程,直到该请求完成,导致定时器无法正常触发后续请求,还会和第一个异步请求产生冲突。 - CodeIgniter会话锁:CodeIgniter默认会在请求期间锁定用户会话,同一个用户的后续请求会被排队,直到第一个请求释放锁,这才是进度请求被卡住的核心原因。
解决步骤
1. 将进度请求改为异步
移除get_progress中Ajax的async: false(默认就是异步),避免阻塞浏览器:
function get_progress() { $.ajax({ url: "/url to get process/", dataType: "json", method: "POST", data: { some_id : some_id }, success:function(data) { // 使用返回的进度值更新UI,示例: $('#progress-bar').css('width', data.progress + '%'); if (data.progress < 100) { return; } // 任务完成,清除定时器 window.clearInterval(timer); }, error: function( data, status, error ) { alert("获取进度失败:" + error); window.clearInterval(timer); } }); }
2. 释放CodeIgniter会话锁
在长运行脚本的控制器方法中,尽早释放会话锁,让后续进度请求能正常处理:
// 初始化会话后立即释放锁 $this->session->sess_write_close(); // 执行长运行逻辑,示例: for ($i = 0; $i <= 100; $i++) { // 更新数据库进度 $this->db->where('id', $some_id)->update('progress_table', ['progress' => $i]); // 模拟耗时操作 sleep(1); }
注意:释放锁后无法再修改会话数据,若长脚本需要修改会话,务必在释放锁前完成。
3. 优化定时器容错
确保请求失败时及时清除定时器,避免无效请求持续触发。
内容的提问来源于stack exchange,提问作者Marius
相关产品推荐
相关产品推荐

