Trampoline 不能支持真正无限递归,但可安全处理深度极大的尾递归——通过将递归转为函数返回+循环执行,使栈深恒定1~2层;必须改写为尾递归形式,所有分支返回thunk,用while循环驱动,注意退出条件与非阻塞分片。

Trampoline 本身不支持真正“无限”递归,但它能安全处理**深度极大、远超调用栈限制的递归逻辑**——关键在于把“递归调用”转为“函数返回+循环执行”,让栈深度恒定在 1~2 层。
必须先改写为尾递归形式
Trampoline 只对尾递归有效。原始递归若不是尾调用(比如 return n * factorial(n-1)),即使套上蹦床也会失效。
- 确保所有递归分支都返回一个函数(thunk),而不是立即调用自身
- 把中间计算结果通过参数传递,避免返回后还要做额外运算
- 例如阶乘要写成
factorial(n - 1, n * acc),而非n * factorial(n - 1)
用 while 循环驱动 thunk 执行
蹦床函数本质是一个外层调度器:它不依赖引擎的尾调用优化(TCO),而是靠手动循环来解包函数链。
- 最小实现只需三行:
while (typeof fn === 'function') fn = fn() - 每次
fn()返回下一个 thunk 或最终值;返回非函数即终止 - 调用时必须用箭头函数或
bind包裹初始调用,防止提前执行爆栈
适配不同数据结构的遍历场景
面对嵌套极深的 JSON、树、链表等,不能直接递归遍历,而应把“下一步该访问谁”封装为 thunk。
- 树遍历:每层返回
() => visit(node.left)或() => visit(node.right),由蹦床逐个触发 - JSON 扁平化:用队列暂存待处理字段,每次 thunk 处理一个节点并推入子字段
- 状态机流转:每个状态返回下一个状态的执行函数,避免深层嵌套回调
注意边界与实际限制
所谓“无限”是逻辑上的,不是无终止。仍需明确退出条件,否则会陷入死循环。
- thunk 内部必须有明确的 base case,返回非函数值(如数字、对象、null)
- 避免在 thunk 中意外触发同步耗时操作(如大量 DOM 操作、大数组遍历),否则虽不爆栈但会阻塞主线程
- 若需真正非阻塞(不卡 UI),应在适当深度后用
setTimeout或queueMicrotask分片执行

















