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

递归检测runningTimers数组长度触发调用栈溢出问题该如何解决?

问题产生原因

JavaScript是单线程事件驱动模型,同步代码的执行优先级远高于setTimeout回调这类宏任务,你的错误由以下逻辑问题共同导致:

  • 你写的checkTimers是同步递归函数,调用时只要runningTimers长度不为0,就会立刻同步调用自身,整个过程始终占用JS主线程,事件循环根本没有空闲时间去执行已经到点的定时器回调,runningTimers永远不会被清空,递归会无限执行。
  • 递归调用没有终止前,调用栈会持续累积,最终超过浏览器预设的最大调用栈限制,抛出RangeError: Maximum call stack size exceeded错误。
  • 额外逻辑漏洞:checkTimers的else分支没有返回值,就算递归能正常终止,你拿到的checkVariable也会是undefined,永远走不到提交逻辑。
可行修复方案

方案1:定时器轮询(改动最小)

把同步递归改成异步轮询,每次间隔一小段时间再检查数组长度,给定时器回调留出执行空间:

// 改造checkTimers,支持传入回调
function checkTimers(callback) {
    if (runningTimers.length < 1) {
        callback(true);
        return;
    }
    // 每隔100ms检查一次,间隔可以自行调整
    setTimeout(() => checkTimers(callback), 100);
}

// 改造提交按钮绑定逻辑
$(document).on("click","#checkoutbtn",function(e) {
    e.preventDefault();
    const $btn = $(this);
    // 先把按钮置为加载状态,避免重复点击
    $btn.html("<i class='fa fa-spinner fa-spin'></i>").prop('disabled',true);
    
    checkTimers(() => {
        $("#cartform").submit();
    });
});

方案2:Promise + async/await(代码更简洁易维护)

把等待逻辑封装成Promise,用异步语法处理:

function waitForTimers() {
    return new Promise(resolve => {
        const check = () => {
            if (runningTimers.length < 1) return resolve();
            setTimeout(check, 100);
        }
        check();
    })
}

// 提交逻辑用async函数
$(document).on("click","#checkoutbtn", async function(e) {
    e.preventDefault();
    const $btn = $(this);
    $btn.html("<i class='fa fa-spinner fa-spin'></i>").prop('disabled',true);
    
    await waitForTimers();
    $("#cartform").submit();
});

方案3:事件触发机制(无轮询性能损耗)

不需要轮询,每次定时器执行完毕时检查是否需要提交,适合对性能要求更高的场景:

// 新增全局标志位,标记用户是否点击了提交
let needSubmit = false;

// 修改定时器回调逻辑
timername[oid] = setTimeout(function() {
    const index = runningTimers.indexOf(oid);
    if (index > -1) {
        runningTimers.splice(index,1);
        console.log("removed");
    }
    // 定时器执行完后检查是否需要提交,且所有定时器都已清空
    if (needSubmit && runningTimers.length === 0) {
        $("#cartform").submit();
    }
    //Ajax code here
},500);

// 提交按钮逻辑
$(document).on("click","#checkoutbtn",function(e) {
    e.preventDefault();
    const $btn = $(this);
    $btn.html("<i class='fa fa-spinner fa-spin'></i>").prop('disabled',true);
    
    // 如果当前没有运行的定时器直接提交,否则设置标志位等定时器跑完自动提交
    if (runningTimers.length === 0) {
        $("#cartform").submit();
    } else {
        needSubmit = true;
    }
});

内容的提问来源于stack exchange,提问作者Saad Bashir

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 10:48:00