You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CodeIgniter实时进度条Ajax阻塞问题求解

问题

我正尝试实现实时显示长进程进度的进度条,大部分功能已完成,但遇到了棘手问题:

点击按钮后触发的JavaScript函数会做两件事:

  1. 发起异步Ajax调用启动长运行脚本,该脚本会在关键节点更新数据库中的进度值(0-100)。
  2. 通过定时器发起同步调用,读取数据库进度来更新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,问题仅在于进度请求需等待长脚本请求完成。

解决方案

问题根源

  1. 同步请求阻塞:get_progress里的Ajax设置了async: false,这会让浏览器阻塞主线程,直到该请求完成,导致定时器无法正常触发后续请求,还会和第一个异步请求产生冲突。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 23:55:31