Express异步调用Cosmos DB构建层级树偶发mechanics未定义错误
问题根因
- 查询结果缺少容错处理:
getCompleteTree执行子文档查询后直接取obj[0]赋值给子节点,未做空值校验。当Cosmos DB出现分区限流、查询超时、临时一致性延迟等情况时,可能返回空结果,导致groupObj.children[index]被赋值为undefined,后续调用splitMechanics时访问undefined的mechanics属性就会触发报错。 - 隐式全局变量污染:
splitMechanics中的循环变量index未加let声明,属于全局变量。多异步逻辑并行执行时,全局index会被互相覆盖,可能导致循环遍历异常、跳过后续节点,甚至访问到不存在的对象属性。 - 属性访问无防御逻辑:
splitMechanics直接访问groupObj.mechanics.length,未先判断mechanics属性是否存在,没有上游逻辑异常的兜底能力。
修复方案
1. 优化getCompleteTree函数
增加查询结果校验,同时改用参数化查询避免SQL注入风险,也可以改成并行查询提升树结构构建效率:
async function getCompleteTree(groupObj) { // 先判断children是有效数组再执行后续逻辑 if (!Array.isArray(groupObj.children) || groupObj.children.length === 0) return // 并行查询所有子节点,提升查询效率 const childQueryTasks = groupObj.children.map(async (child) => { const querySpec = { query: "SELECT c.id, c.parent, c.name, c.mechanics, c.children FROM c WHERE c.id = @childId", parameters: [{ name: "@childId", value: child.id }] } const { resources: childRes } = await Groups.items.query(querySpec).fetchAll() // 空结果兜底,即使查询失败也保留基础结构,避免后续报错 return childRes?.[0] || { ...child, mechanics: [], children: [] } }) // 等待所有子节点查询完成 groupObj.children = await Promise.all(childQueryTasks) // 并行递归处理所有子节点的子树 await Promise.all(groupObj.children.map(child => getCompleteTree(child))) }
2. 修复splitMechanics函数
修复全局变量问题,增加属性防御校验:
function splitMechanics(groupObj) { // 校验mechanics是有效数组再遍历 if (Array.isArray(groupObj.mechanics)) { // 加let声明index,避免全局变量污染 for (let index = 0; index < groupObj.mechanics.length; index++) { // 原有同步处理逻辑 } } // 校验children是有效数组再递归 if (Array.isArray(groupObj.children)) { groupObj.children.forEach(obj => splitMechanics(obj)) } }
内容的提问来源于stack exchange,提问作者Jeppe Christensen
相关产品推荐
相关产品推荐

