本文主要结合实例,介绍下调用栈溢出的问题,即对应解决方案

规则:Chrome/V8 引擎的调用栈上限约 10000 层,超过后直接抛出 Maximum call stack size exceeded 错误;代码终止执行,无法继续递归。

实例解释:

let stackCount = 0; // 记录递归层数

// 同步递归函数(无终止条件,会无限递归)
function recursiveFunc() {
  stackCount++;
  recursiveFunc(); // 函数最后一步又调用自己 → 同步递归
}

// 捕获栈溢出错误
try {
  recursiveFunc();
} catch (error) {
  console.log('递归层数:', stackCount); // Chrome中约 10000 层
  console.log('错误信息:', error.message); // "Maximum call stack size exceeded"
}

控制台报错

原因解释:
每次调用 recursiveFunc(),JS 引擎会在「调用栈」中创建一个「栈帧」(保存函数的执行状态);同步递归时,新的栈帧会不断叠加,直到调用栈的内存被占满;

如何规避

用「循环 + 变量」替代递归,调用栈始终只有 1 层
let loopCount = 0;

// 循环替代递归(调用栈始终只有1层)
function loopFunc() {
  while (true) { // 无限循环(模拟无限递归)
    loopCount++;
    // 手动终止:避免死循环卡死,仅做演示
    if (loopCount === 20000) {
      console.log('迭代执行层数:', loopCount); // 20000层(无溢出)
      break;
    }
  }
}

loopFunc(); // 执行正常,无错误
异步递归
let asyncCount = 0;

// 异步递归函数
async function asyncRecursiveFunc() {
  asyncCount++;
  
  // 手动终止:避免无限异步递归
  if (asyncCount === 20000) {
    console.log('异步递归层数:', asyncCount); // 20000层(无溢出)
    return;
  }

  // 关键:setTimeout 清空当前栈,新递归在新栈中执行
  await new Promise(resolve => setTimeout(resolve, 0));
  await asyncRecursiveFunc();
}

asyncRecursiveFunc(); // 执行正常,无错误

setTimeout讲一个resolve塞入宏任务队列,await一个 asyncRecursiveFunc函数执行。此时,主线程栈空,拿出resolve,继续执行,完美屏蔽溢出问题。