当在两个数组之间找到匹配项时停止迭代并 return true

Stop iterating and return true when a match is found between two arrays

我有两个数据集,一个在 indexedDB 中,一个在 PouchDB 中(是的,我知道 PouchDB 是 indexedDB 的一种实现)。

indexedDB中的是房间列表,通过上一页存入indexedDB,显示在当前页

PouchDB中的是房间审核员记录的房间使用日志。我想遍历第一个列表,并检查每个项目是否出现在已审核房间列表中。如果确实出现了,我想设置一个标志来表示。

这是我的 Javascript。 (我在浏览器中有 运行 这个,它在这个过程中的某个时刻确实 return true,因为控制台日志输出显示了这一点,但是没有针对列表项设置标志。)

我想知道它是否会继续遍历审计记录并覆盖 "true" 值?

这是查询indexedDB的函数,调用查询PouchDB的函数:

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"});
        var index = itemStore.createIndex("rooms", ["route_number"]);
    };

    openRequest.onerror = function(event) {
        console.error(event);
    };

    openRequest.onsuccess = function (event) {
        var db = openRequest.result;
        db.onerror = function(event) {
            // Generic error handler for all errors targeted at this database's requests
            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");
        var index = itemStore.index("rooms", ["route_number"]);
        console.log('DB opened');
        var intRouteNumber = parseInt(routeNumber);
        //var range = IDBKeyRange.only(intRouteNumber);

        itemStore.openCursor().onsuccess = function(event) {
            var cursor = event.target.result;
            if(cursor) {
                var audited;
                if(cursor.value.route_number == routeNumber) {
                    if (checkIfAudited(cursor.value.room_seq)) {
                        var audited = ' <span class="checked"><i class="fa fa-check"></i></span>';
                    } else {
                        var audited = "";
                    }
                    $('#mylist').append("<li id="+ cursor.value.room_id +" rel="+ cursor.value.room_seq +"> " + '<small>'+ cursor.value.room_seq + '.&nbsp;</small><a href="/static?action=edit&amp;room_id='+ cursor.value.room_id +'&amp;route_number='+ cursor.value.route_number +'&amp;sequence='+ cursor.value.room_seq +'&amp;roomname='+ cursor.value.room_name +'&amp;capacity='+ cursor.value.room_capacity +'">' + cursor.value.room_name + '</a>'+audited+'</li> ');
                }

                cursor.continue();
            } else {
                console.log('Entries all displayed.');
                if(!($.jStorage.get('reverseroute', ''))) {
                    reverseroute = 'asc';

                } else {
                    reverseroute = $.jStorage.get('reverseroute', '');
                }
                appendHref(reverseroute);
            }
        };

        // Close the db when the transaction is done
        transaction.oncomplete = function() {
            db.close();
        };
    };
}

这是查询 PouchDB 以查看其是否已被审计的函数:

function checkIfAudited(roomseq) {
    var today = new Date();
    if(is_BST(today) == true) {
        var currentHour = today.getHours()+1;
    } else {
        var currentHour = today.getHours();
    }
    var currentDay = today.getDate();
    var currentMonth = today.getMonth();

    options = {},
    that = this,
    pdb = new PouchDB('pouchroomusage');
    options.include_docs = true;
    var pouchOpts = {
      skipSetup: true
    };
    var opts = {live: true};

    pdb.allDocs(options, function (error, response) {
        response.rows.some(function(row){
            var auditTime = new Date(row.doc.timestamp);
            var auditHour = auditTime.getUTCHours();
            var auditDay = auditTime.getDate();
            var auditMonth = auditTime.getMonth();
            if(row.doc.sequence == roomseq && currentHour == auditHour && currentDay == auditDay && currentMonth == auditMonth) {
                var isAudited = true;   
                console.log('RoomSeq: ' + roomseq + '; auditHour: ' + auditHour + '; currentHour: ' + currentHour + '; auditDay: ' + auditDay); 
                console.log('currentDay: ' + currentDay + '; auditMonth: ' + auditMonth + '; currentMonth: ' + currentMonth + '; isAudited: ' + isAudited);
            } else {
                var isAudited = false;
                console.log('No matches');
            }
            return isAudited;
        });
    });
}

我已经阅读了许多关于比较两个数组的其他问题和答案。

虽然我不知道如何将 for 循环与 pdb.allDocs 一起使用 :(

这是 console.log 的输出:

49 No matches

RoomSeq: 1; auditHour: 14; currentHour: 14; auditDay: 16 currentDay: 16; auditMonth: 0; currentMonth: 0; isAudited: true

2300 No matches

那么,当第二个函数在 PouchDB 中命中匹配记录时,如何让第二个函数停止并 return 为真?

在我看来 pouchdb 方法 alldocs 是异步的。 但是您以同步方式测试试听。因此,无论 pdb.alldocs 回调函数 returns 将在 checkIfAudited 已经 returned 之后被 returned。因此 checkIfAudited 总是 returns undefined.

在我看来,您应该在 temStore.openCursor().onsuccess 中只创建一次 pouchdb 实例。然后你需要在 checkIfAudited 函数中正确地 return 审计状态。

例如,您可以执行以下操作:

itemStore.openCursor().onsuccess = function(event) {

  var cursor = event.target.result;

  if (cursor) {

    if (cursor.value.route_number == routeNumber) {

      var audited;
      options = {},
      pdb = new PouchDB('pouchroomusage');
      options.include_docs = true;

      pdb.allDocs(options, function (error, allDocsResponse) {

        if (checkIfAudited(allDocsResponse, cursor.value.room_seq)) audited = ' <span class="checked"><i class="fa fa-check"></i></span>'

        else audited = "";

        $('#mylist').append("<li id="+ cursor.value.room_id +" rel="+ cursor.value.room_seq +"> " + '<small>'+ cursor.value.room_seq + '.&nbsp;</small><a href="/static?action=edit&amp;room_id='+ cursor.value.room_id +'&amp;route_number='+ cursor.value.route_number +'&amp;sequence='+ cursor.value.room_seq +'&amp;roomname='+ cursor.value.room_name +'&amp;capacity='+ cursor.value.room_capacity +'">' + cursor.value.room_name + '</a>'+audited+'</li> ');

      });

    };

    cursor.continue();

  } else {

    console.log('Entries all displayed.');

    if(!($.jStorage.get('reverseroute', ''))) reverseroute = 'asc'

    else reverseroute = $.jStorage.get('reverseroute', '');

    appendHref(reverseroute);

  };


};

对于 checkIfAudited:

function checkIfAudited(allDocs, roomseq) {


    var today = new Date();
    if(is_BST(today) == true) {
        var currentHour = today.getHours()+1;
    } else {
        var currentHour = today.getHours();
    }
    var currentDay = today.getDate();
    var currentMonth = today.getMonth();

    for (i=0; i<allDocs.rows.length; i++) {
      var row = allDocs.rows[i];

      var auditTime = new Date(row.doc.timestamp);
      var auditHour = auditTime.getUTCHours();
      var auditDay = auditTime.getDate();
      var auditMonth = auditTime.getMonth();
      if(row.doc.sequence == roomseq && currentHour == auditHour && currentDay == auditDay && currentMonth == auditMonth) {
        console.log('RoomSeq: ' + roomseq + '; auditHour: ' + auditHour + '; currentHour: ' + currentHour + '; auditDay: ' + auditDay); 
        console.log('currentDay: ' + currentDay + '; auditMonth: ' + auditMonth + '; currentMonth: ' + currentMonth + '; isAudited: ' + isAudited);
        return true;    ///// <---- return that it is audited
      } else {
        console.log('No matches');
      };

    });

    return false    ///// <---- return false if no iteration has matched
}

首先,我不会太喜欢利用 Array.prototype.some 的短路行为。使用您可用的本机功能。 indexedDB 提供了一种内置的方法来停止推进游标,或仅从存储中加载有限数量的对象。

其次,当您只对其中的几个对象感兴趣时,您可能希望避免从存储中加载所有对象。使用光标在商店中行走。由于您似乎希望在满足某些条件时停止迭代,所以此时不​​要调用 cursor.continue。

第三,即使决定首先从存储中加载所有对象,使用 for 循环也比利用 some 要好得多。通过利用,我的意思是以不同于预期的方式使用该功能。我敢打赌,如果你恢复使用带有 break 语句的 for 循环,代码会更清晰,因此你会更容易理解为什么循环不会在你期望的时候中断。

第四,我会花时间将 indexedDB 查询的结果附加到中间数据结构,如数组,而不是立即与 DOM 交互。它会分离更多的东西,你会发现代码更容易调试。

第五,将异步调用与 indexedDB 混合使用时,您应该非常小心。众所周知,当您交错调用其他承诺时,indexedDB 会出现问题。

这是我经过多次调整后得到的结果。

现在它对每个 <li> 添加了不止一次 <span class="checked"><i class="fa fa-check"></i></span>,但至少它添加到每个 <li>.

所以我对 CSS 做了一点修改,只显示一个 span.checked:

.checked {
    color: #fff;
    background-color: #006338;
    border-radius: 50%;
    padding: 2px 3px;
}

/* only display the first instance of checked */
li > span.checked ~ .checked {
    display: none;
}

(我还发现并修复了脚本中的另一个错误,我没有设置 route_numberroom_id。)

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"});
        var index = itemStore.createIndex("rooms", ["route_number"]);
    };

    openRequest.onerror = function(event) {
        console.error(event);
    };

    openRequest.onsuccess = function (event) {
        var db = openRequest.result;
        db.onerror = function(event) {
            // Generic error handler for all errors targeted at this database's requests
            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");
        var index = itemStore.index("rooms", ["route_number"]);
        console.log('DB opened');
        var intRouteNumber = parseInt(routeNumber);
        //var range = IDBKeyRange.only(intRouteNumber);

        itemStore.openCursor().onsuccess = function(event) {
            var cursor = event.target.result;
            var audited = "";
            if(cursor) {
              if(cursor.value.route_number == routeNumber) {

                $('#mylist').append("<li id="+ cursor.value.room_id +" rel="+ cursor.value.room_seq +"> " + '<small>'+ cursor.value.room_seq + '.&nbsp;</small><a href="/static?action=edit&amp;room_id='+ cursor.value.room_id +'&amp;route_number='+ cursor.value.route_number +'&amp;sequence='+ cursor.value.room_seq +'&amp;roomname='+ cursor.value.room_name +'&amp;capacity='+ cursor.value.room_capacity +'">' + cursor.value.room_name + '</a></li> ');


              }

              cursor.continue();

            } else {
                console.log('Entries all displayed.');
                if(!($.jStorage.get('reverseroute', ''))) {
                    reverseroute = 'asc';
                } else {
                    reverseroute = $.jStorage.get('reverseroute', '');
                }
                appendHref(reverseroute);

                asyncCallToPouchDb();
            }
        };


        // Close the db when the transaction is done
        transaction.oncomplete = function() {
            db.close();
        };
    };
}


function asyncCallToPouchDb() { 
    $('#mylist li').each(function(){
        var audited = "";
        var room_id = $(this).attr('id');
        var thisLi = $(this);
        audited = callPouchDb(room_id, thisLi);

    });
}


function callPouchDb(room_id, thisLi) {
    options = {},
    pdb = new PouchDB('pouchroomusage');
    options.include_docs = true;
    var audited = "";
    //return new Promise(resolve => {
         pdb.allDocs(options, function (error, response) {
            result = response.rows;
            for (i = 0; i < result.length; i++) { 
                if (checkIfAudited(result[i], room_id)) {
                    audited = ' <span class="checked"><i class="fa fa-check"></i></span>';
                } 
                thisLi.append(audited);
            } 
            //thisLi.append(audited);
            /*end pdb.allDocs*/
        }).then(function (result) {

          // handle result
          console.log(result);

        }).catch(function (err) {
          console.log(err);
        });

    // });

}

function checkIfAudited(row, room_id) {

    var today = new Date();
    if(is_BST(today) == true) {
        var currentHour = today.getHours()+1;
    } else {
        var currentHour = today.getHours();
    }
    var currentDay = today.getDate();
    var currentMonth = today.getMonth();
    var currentYear = today.getYear();

    var isAudited = false;    ///// <---- define isAudited outside of db iteration scope

      var auditTime = new Date(row.doc.timestamp);
      var auditHour = auditTime.getUTCHours();
      var auditDay = auditTime.getDate();
      var auditMonth = auditTime.getMonth();
      var auditYear = auditTime.getYear();
      if(row.doc.room_id == room_id && currentHour == auditHour && currentDay == auditDay && currentMonth == auditMonth && currentYear == auditYear) {
        isAudited = true;   
        // debug 
   //     console.log('RoomSeq: ' + roomseq + '; auditHour: ' + auditHour + '; currentHour: ' + currentHour + '; auditDay: ' + auditDay); 
   //     console.log('currentDay: ' + currentDay + '; auditMonth: ' + auditMonth + '; currentMonth: ' + currentMonth + '; isAudited: ' + isAudited);
      } else {
         console.log('No matches');
      };

    return isAudited 
}