【问题标题】:Stop iterating and return true when a match is found between two arrays在两个数组之间找到匹配项时停止迭代并返回 true
【发布时间】:2018-01-23 00:49:01
【问题描述】:

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

indexedDB中的一个是房间列表,通过前一页存储在indexedDB中,显示在当前页。

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

这是我的 Javascript。 (我已经在浏览器中运行了它,它确实在过程中的某个时刻返回 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 没有匹配项

房间序列:1;审计时间:14;当前时间:14;审计日:16 当前日:16;审计月:0;当前月份:0;已审核:真实

2300 没有匹配项

那么,如何让第二个函数在 PouchDB 中遇到匹配记录时停止并返回 true?

【问题讨论】:

  • 还是因为我返回了变量isAudited而调用函数不知道如何处理它?

标签: javascript arrays indexeddb pouchdb


【解决方案1】:

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

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

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

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

第五是在将异步调用与 indexedDB 混合在一起时应该非常小心。众所周知,当您将调用交错到其他 Promise 时,indexedDB 会出现问题。

【讨论】:

  • 感谢这一点,尤其是第四点 - 当我尝试交错调用时它疯了,所以最终将 pdb.allDocs 调用完全放在 getRoomsInRoute() 函数之外。让我们看看这是否有效:)
【解决方案2】:

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

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

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

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
}

【讨论】:

  • 这是一个非常优雅的解决方案,但我收到一个错误:Uncaught (in promise) DOMException: Failed to execute 'continue' on 'IDBCursor': The transaction has finished. 我想知道是不是因为您在 pdb.allDocs 中嵌套了 IDB 游标?
  • 我不知道这个错误的确切来源。但是,您可以将 pouchdb 实例创建和 pdb.allDocs 放在 if(cursor) 甚至 if(cursor.value.route_number == routeNumber) 中。那么除了创建 DOM 元素之外,您不应该影响代码的任何其他部分来测试试听,并且异步完成可能并不重要。
  • 我想就是这样 - 只需将 $('#mylist').append("... 放在 pdb.allDocs 函数之外
  • 如果你从pdb.allDocs回调中取出$('#mylist'),它就不会再工作了。由于pdb.allDocs 的回调是异步的,您可以在设置audited 值之前附加显示audited 值的dom 元素。
  • 我已经相应地编辑了我的答案。我仍然建议您将代码更多地分割成用于不同功能的单独函数。我认为它会使调试/改进更清晰、更容易。
【解决方案3】:

这是我经过多次调整后最终得到的。

现在每个&lt;li&gt; 不止一次添加&lt;span class="checked"&gt;&lt;i class="fa fa-check"&gt;&lt;/i&gt;&lt;/span&gt;,但至少它添加到每个&lt;li&gt;

所以我对 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 
}
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-07
相关资源
最近更新 更多