在traverse的forEach中使用async函数出现调用栈溢出错误如何解决
问题原因
traverse 包的 forEach 是同步遍历方法,设计上不支持异步回调。你传入 async 函数后,方法内部不会等待 Promise 执行完成,会持续同步触发递归遍历,同时 async 函数的执行上下文无法被正常释放,当JSON结构深度足够时就会触发 Maximum call stack size exceeded 栈溢出错误。
另外你提供的代码存在语法问题:for(var i=0 i<10; i++)= 缺少分号、多了等号,不过这不是栈溢出的直接诱因。
解决方案
方案1:手写异步递归遍历
如果必须在遍历节点的同时执行异步逻辑,自己实现支持异步的遍历方法即可,示例代码如下:
async function traverseAsync(obj, asyncCallback) { // 先执行当前节点的异步回调 await asyncCallback(obj); // 递归遍历子节点 if (obj && typeof obj === 'object') { for (const val of Object.values(obj)) { await traverseAsync(val, asyncCallback); } } } // 调用示例 await traverseAsync(json, async (value) => { for(var i=0; i<10; i++){ const result = await someFunction(i); const result2 = doSomething(result); } const r = result2; })
方案2:先收集节点再批量异步处理
如果不想改动遍历逻辑,可以先用 traverse 同步收集所有需要处理的节点,再遍历节点列表执行异步操作:
const allNodes = []; // 同步收集所有节点 traverse(json).forEach(value => { allNodes.push(value); }); // 异步处理所有节点 for (const value of allNodes) { for(var i=0; i<10; i++){ const result = await someFunction(i); const result2 = doSomething(result); } const r = result2; }
注意事项
不要给同步迭代方法(包括 traverse 的 forEach、原生数组的 forEach 等)传入 async 回调,这类方法不会等待 Promise 执行完成,会导致逻辑异常、内存泄漏或者栈溢出问题,异步迭代请使用支持异步的遍历方案,比如 for...of 配合 await。
内容的提问来源于stack exchange,提问作者daniel
相关产品推荐
相关产品推荐

