循环获取MongoDB Realm元数据后异步查询每条对应数据统计数的实现问题
核心问题说明
原代码使用var声明循环变量,存在变量提升问题,异步请求回调触发时无法拿到对应轮次的正确参数;同时需要将异步查询结果和对应DOM元素绑定,以下是三种可直接落地的方案:
方案1:最小改动(串行执行,代码逻辑最直观)
仅修改原循环的变量声明和新增异步查询逻辑即可:
mongo({ collection: "metadata", action: "find", criteria: { query: {}}, }).then(async (metadata) => { // 把var改为let,创建块级作用域绑定每轮循环的变量 for (let i = 0; i < metadata.length; i++) { const oneMeta = metadata[i]; const subjectName = oneMeta.name; const subjectCode = oneMeta.code; // 模板字符串可以直接用插值语法,不用字符串拼接 const blockHTML = ` <div> <span class="badge badge-danger">${subjectName}</span> <span class="badge badge-dark">${subjectCode}</span> </div>`; const oneSubject = document.createElement("div"); oneSubject.id = "sub_" + subjectCode; oneSubject.innerHTML = blockHTML; subjectOutput.appendChild(oneSubject); // 执行当前条目的count查询 const count = await mongo({ collection: "actualData", action: "count", criteria: { query: {subjectId: subjectCode }} }); // 追加统计数 const countSpan = document.createElement("span"); countSpan.className = "badge badge-secondary"; // 可自定义样式 countSpan.textContent = count; oneSubject.appendChild(countSpan); } });
方案2:forEach + then 并行执行(无需async/await兼容旧环境)
用forEach遍历替代for循环,天然具备独立作用域,无需处理变量提升问题:
mongo({ collection: "metadata", action: "find", criteria: { query: {}}, }).then((metadata) => { metadata.forEach(oneMeta => { const subjectName = oneMeta.name; const subjectCode = oneMeta.code; const blockHTML = ` <div> <span class="badge badge-danger">${subjectName}</span> <span class="badge badge-dark">${subjectCode}</span> </div>`; const oneSubject = document.createElement("div"); oneSubject.id = "sub_" + subjectCode; oneSubject.innerHTML = blockHTML; subjectOutput.appendChild(oneSubject); // 异步查询count,回调直接操作当前轮的DOM元素 mongo({ collection: "actualData", action: "count", criteria: { query: {subjectId: subjectCode }} }).then(count => { const countSpan = document.createElement("span"); countSpan.textContent = count; oneSubject.appendChild(countSpan); }); }) });
方案3:Promise.all 批量并行(性能最优,适合数据量较大的场景)
先渲染所有基础DOM,再批量发起查询,等所有查询完成后统一更新,减少DOM重绘:
mongo({ collection: "metadata", action: "find", criteria: { query: {}}, }).then(async (metadata) => { const subjectElements = []; // 先渲染所有基础条目,同时生成所有count查询的Promise const countPromises = metadata.map(oneMeta => { const subjectName = oneMeta.name; const subjectCode = oneMeta.code; const blockHTML = ` <div> <span class="badge badge-danger">${subjectName}</span> <span class="badge badge-dark">${subjectCode}</span> </div>`; const oneSubject = document.createElement("div"); oneSubject.id = "sub_" + subjectCode; oneSubject.innerHTML = blockHTML; subjectOutput.appendChild(oneSubject); subjectElements.push(oneSubject); // 返回查询Promise return mongo({ collection: "actualData", action: "count", criteria: { query: {subjectId: subjectCode }} }); }); // 等待所有count查询完成 const countList = await Promise.all(countPromises); // 批量更新统计数 countList.forEach((count, index) => { const countSpan = document.createElement("span"); countSpan.textContent = count; subjectElements[index].appendChild(countSpan); }); });
内容的提问来源于stack exchange,提问作者NJBR
相关产品推荐
相关产品推荐

