如何让PouchDB查询函数匹配到记录时停止迭代并返回true?
问题根源:异步操作的返回值处理错误
你的核心问题在于checkIfAudited函数里调用的pdb.allDocs是异步操作,但你试图同步获取它的返回值——这根本行不通,因为函数会在PouchDB查询完成前就执行完毕,返回的是undefined,而不是你期望的true/false。另外,some方法里的isAudited变量作用域也有问题,导致无法正确终止循环并返回结果。
下面是分步修复方案:
1. 重构checkIfAudited为返回Promise的异步函数
把异步查询逻辑包装成Promise,这样我们可以等待查询完成后再获取结果:
function checkIfAudited(roomseq) { return new Promise((resolve, reject) => { var today = new Date(); var currentHour = is_BST(today) ? today.getHours() + 1 : today.getHours(); var currentDay = today.getDate(); var currentMonth = today.getMonth(); const pdb = new PouchDB('pouchroomusage'); const options = { include_docs: true }; pdb.allDocs(options, function(error, response) { if (error) { console.error('PouchDB query error:', error); reject(false); // 出错时返回false或者根据需求处理 return; } // 使用some方法遍历,找到匹配项就立即终止并返回true const isAudited = response.rows.some(row => { const auditTime = new Date(row.doc.timestamp); const auditHour = auditTime.getUTCHours(); const auditDay = auditTime.getDate(); const auditMonth = auditTime.getMonth(); const matches = row.doc.sequence == roomseq && currentHour == auditHour && currentDay == auditDay && currentMonth == auditMonth; if (matches) { console.log('RoomSeq: ' + roomseq + '; auditHour: ' + auditHour + '; currentHour: ' + currentHour + '; auditDay: ' + auditDay); console.log('currentDay: ' + currentDay + '; auditMonth: ' + auditMonth + '; currentMonth: ' + currentMonth + '; isAudited: true'); } else { console.log('No matches for roomseq:', roomseq); } return matches; // 匹配到就返回true,终止some循环 }); resolve(isAudited); // 将最终结果返回 }); }); }
修改点说明:
- 用
Promise包裹异步查询,成功时resolve结果,失败时reject - 简化了
currentHour的判断逻辑(三元运算符更简洁) - 把
isAudited直接作为some的返回值,避免变量作用域问题,匹配到就立即终止循环 - 增加了错误处理:如果PouchDB查询出错,直接返回
false(你可以根据需求调整错误处理逻辑)
2. 修改getRoomsInRoute中的cursor遍历逻辑,支持异步调用
因为checkIfAudited现在是异步函数,我们需要用async/await来等待它的结果,所以要把cursor的回调改成async函数:
function getRoomsInRoute() { var routeNumber = $.jStorage.get('currentRoute', ''); var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB || window.shimIndexedDB; openRequest = window.indexedDB.open("rooms", 1); openRequest.onupgradeneeded = function() { var db = openRequest.result; var itemStore = db.createObjectStore("rooms", {keyPath: "room_id"}); itemStore.createIndex("rooms", ["route_number"]); }; openRequest.onerror = function(event) { console.error(event); }; openRequest.onsuccess = async function (event) { // 这里改成async函数 var db = openRequest.result; db.onerror = function(event) { console.error(event.target); console.log("Database error: " + event.target.error.name || event.target.error || event.target.errorCode); }; var transaction = db.transaction(['rooms'], "readwrite"); var itemStore = transaction.objectStore("rooms"); console.log('DB opened'); var intRouteNumber = parseInt(routeNumber); itemStore.openCursor().onsuccess = async function(event) { // 这里也改成async函数 var cursor = event.target.result; if(cursor) { if(cursor.value.route_number == routeNumber) { // 等待checkIfAudited的结果 const isAudited = await checkIfAudited(cursor.value.room_seq); const audited = isAudited ? ' <span class="checked"><i class="fa fa-check"></i></span>' : ''; $('#mylist').append(`<li id="${cursor.value.room_id}" rel="${cursor.value.room_seq}"> <small>${cursor.value.room_seq}. </small> <a href="/static?action=edit&room_id=${cursor.value.room_id}&route_number=${cursor.value.route_number}&sequence=${cursor.value.room_seq}&roomname=${cursor.value.room_name}&capacity=${cursor.value.room_capacity}"> ${cursor.value.room_name} </a>${audited} </li>`); } cursor.continue(); } else { console.log('Entries all displayed.'); const reverseroute = $.jStorage.get('reverseroute', '') || 'asc'; appendHref(reverseroute); } }; transaction.oncomplete = function() { db.close(); }; }; }
修改点说明:
- 把
openRequest.onsuccess和itemStore.openCursor().onsuccess的回调都改成async函数,这样就能用await等待checkIfAudited的结果 - 用模板字符串替代字符串拼接,代码更易读且不易出错
- 简化了
reverseroute的判断逻辑 - 等待
checkIfAudited返回结果后,再决定是否添加审计标记,避免了之前同步调用导致的错误
额外优化建议
如果房间数量很多,逐个调用checkIfAudited会产生大量PouchDB查询,建议一次性把所有符合条件的审计记录查出来,在内存中做匹配,性能会好很多:
// 先一次性获取今日当前小时内的所有已审计房间序号 async function getTodayAuditedRooms() { const today = new Date(); const currentHour = is_BST(today) ? today.getHours() + 1 : today.getHours(); const currentDay = today.getDate(); const currentMonth = today.getMonth(); const pdb = new PouchDB('pouchroomusage'); const response = await pdb.allDocs({ include_docs: true }); return response.rows .map(row => row.doc) .filter(doc => { const auditTime = new Date(doc.timestamp); return doc.sequence && auditTime.getUTCHours() === currentHour && auditTime.getDate() === currentDay && auditTime.getMonth() === currentMonth; }) .map(doc => doc.sequence); // 只保留房间序号,方便后续查找 } // 然后在getRoomsInRoute中复用这个结果 openRequest.onsuccess = async function (event) { // ... 其他代码 ... const auditedRoomSeqs = await getTodayAuditedRooms(); // 一次性获取所有已审计序号 itemStore.openCursor().onsuccess = function(event) { var cursor = event.target.result; if(cursor) { if(cursor.value.route_number == routeNumber) { const isAudited = auditedRoomSeqs.includes(cursor.value.room_seq); const audited = isAudited ? ' <span class="checked"><i class="fa fa-check"></i></span>' : ''; // ... 拼接HTML并添加到列表 ... } cursor.continue(); } // ... 其他代码 ... }; };
这种方式只需要一次PouchDB查询,避免了重复请求,适合房间数量较多的场景。
内容的提问来源于stack exchange,提问作者Yvonne Aburrow
相关产品推荐
相关产品推荐

