递归函数导致页面卡死,怎么优化?

司徒智越 阅读 61

我在写一个树形结构的遍历功能,用了递归处理子节点,但数据一多页面就直接卡住不动了。

试过加个深度限制,但业务上又不能丢数据。有没有办法把递归改成非阻塞的方式?比如用循环或者分片处理?

这是我现在用的递归代码:

function traverse(node) {
  if (!node.children) return;
  node.children.forEach(child => {
    // 处理逻辑
    traverse(child);
  });
}
我来解答 赞 6 收藏
二维码
手机扫码查看
1 条解答
令狐秀花
页面卡死是因为递归调用栈太深,JS 单线程一跑起来就堵死了,得把同步递归改成异步分片执行,让浏览器有机会喘口气。

核心思路是用队列模拟递归,配合 setTimeout 或 requestAnimationFrame 把任务拆成小块,比如这样:

function traverseAsync(root, processNode, done) {
const queue = [root];
let batchCount = 0;

function processBatch() {
const maxPerBatch = 100; // 每批处理多少个节点,可调
let processed = 0;

while (queue.length > 0 && processed < maxPerBatch) {
const node = queue.shift();
processNode(node); // 你的处理逻辑

if (node.children && node.children.length > 0) {
queue.push(...node.children);
}
processed++;
}

if (queue.length > 0) {
batchCount++;
// 每批之间让出主线程,避免卡顿
requestAnimationFrame(processBatch);
} else {
done && done(batchCount);
}
}

processBatch();
}

// 使用
traverseAsync(rootNode, node => {
// 这里写你原来的处理逻辑,比如计算、渲染等
}, () => {
console.log('遍历完成,共分', batchCount, '批处理');
});


如果数据量特别大,光前端分片可能也不够,得考虑数据是不是该从后端按需加载——比如树形结构只展开当前层级,用户点开再查子节点,数据库层面用递归 CTE 或预存路径字段(如 materialized path)来加速查询。

另外提醒一句,如果遍历只是为了生成某个结果(比如flatten list),其实用迭代队列更高效;如果是为了渲染树,建议用虚拟滚动或者懒加载,别一次性把整棵树塞进 DOM。
点赞 4
2026-02-24 21:07