蹦床模式通过任务队列与循环驱动实现非递归的无限任务调度,每次执行一个函数并可动态添加新任务,避免栈溢出;需配合微任务、暂停控制和切片机制保障响应性与可控性。

蹦床模式(Trampoline)是一种避免栈溢出的递归技巧,它把递归调用“压平”为循环,每次只执行一个任务,返回下一个待执行的任务函数,由外层循环统一调度。实现无限任务循环的关键不是真递归,而是用循环+函数队列模拟“延后执行”,让每个任务在栈帧清空后再启动下一个。
核心结构:任务队列 + 循环驱动
所有待执行任务以函数形式存入队列(如数组),主循环不断取出并调用,新任务可随时推入队列末尾,形成可持续运行的闭环。
- 初始化一个空数组作为任务队列(tasks)
- 写一个持续运行的 while 循环,只要队列非空就取首个函数执行
- 每个任务函数执行后,可向队列 push 新任务(包括自己,实现“重复”)
- 确保每次任务执行完立即返回,不阻塞循环,也不深层调用其他任务
基础示例:打印计数器(无阻塞版)
下面是一个典型的蹦床无限循环,每轮打印一个数字,并自动安排下一轮:
const tasks = [];
function schedule(task) {
tasks.push(task);
}
function runLoop() {
while (tasks.length > 0) {
const task = tasks.shift();
if (typeof task === 'function') task();
}
}
// 启动第一个任务
let count = 0;
schedule(() => {
console.log('tick:', count++);
schedule(() => {
console.log('tick:', count++);
schedule(() => {
// 可继续嵌套,但更推荐解耦写法
});
});
});
// 启动循环(注意:需在事件循环空闲时调用,避免阻塞主线程)
setTimeout(runLoop, 0);
实用增强:支持异步与暂停控制
纯同步蹦床容易饿死其他任务;实际应用中建议结合 Promise 或 queueMicrotask,让浏览器有机会处理渲染、输入等事件。
- 用 queueMicrotask 替代 tasks.shift() 立即执行,把下个任务挂到微任务队列
- 加入 running 开关,允许外部暂停/恢复循环
- 任务函数返回 Promise 时,用 await 等待完成再调度下一个(需用 async 函数包装循环)
- 避免在单次任务中做大量计算;耗时操作应切片或移交 Web Worker
注意事项:别把它当成“万能后台线程”
蹦床本质仍是单线程调度,无法真正并行。它解决的是调用栈深度问题,不是 CPU 占用问题。
- 若某任务执行时间过长(如 >16ms),会导致页面卡顿,应主动 yield(如用 setTimeout(fn, 0) 切片)
- 无限循环必须有退出条件或外部中断机制(如监听用户操作、超时、状态变更)
- 不要在任务里直接递归调用自身——那又退回了原始递归,失去蹦床意义
- 调试时注意:堆栈追踪只显示当前任务,历史任务已出栈,需靠日志或状态标记定位











