Search code examples
javascriptjqueryloopsbrowserinfinite

JavaScript Loop doesn't exit


I've tried everything I can think of.

I'm building a sort of chat bot for IMVU, using injected JavaScript on the IMVU mobile website. I have a loop to crawl the messages received, and search for certain key terms, like a message beginning with a slash (/) to indicate a command to the bot.

When certain commands are used, I have a problem that the bot seems to get stuck in the loop, almost as if the index of the for loop is being modified inside the loop. The code is included below.

If you need more, ask, and if you find something that might be causing the problem, please let me know. I'm at my wit's end.

Just for a note: jQuery is properly injected, all my variables are there, no errors in the debug console, and running under Chrome 41.0.2272.101m on Windows 7 x64.

function verifyCommand() {
  if (document.getElementsByClassName("message-list-item").length > last_cmd_count && !processing_commands) {
    var new_length = $('.message-list .message-list-item').length;
    console.log("Begin processing commands... ** SYSTEM LOCK **");
    console.log(new_length);
    for (var i = last_cmd_count; i < (new_length); i++) {
      processing_commands = true;
      try {
        var callinguser = $('.message-list .message-list-item .header .username .username-text')[i].innerText.replace("Guest_", "");
        var messagetext = $('.message-list .message-list-item .message .message-text')[i].innerText
        if (callinguser != "USERNAME REMOVED") {
          if (messagetext.substr(0, 1) == "/") {
            if (strContains(callinguser, "IMVU User")) {
              die();
            }
            processCommand(messagetext.substr(1), callinguser);
          } else {
            if (messagetext.toLowerCase().indexOf('roomgreet') > -1 || messagetext.toLowerCase().indexOf('room greet') > -1) {
              if (detectFlirt()) {
                sendMsgRaw('Please do not hit on me, ' + callinguser + '.');
                if (!isAdmin(callinguser)) {
                  logIdiot(callinguser);
                }
              } else if (strContains(messagetext, 'what is ')) {
                sendMsgRaw('Please use /solve or /advsolve for math.');
              } else {
                if (callinguser != "USERNAME REMOVED") {
                  ident();
                }
              }
            }
            if (strContains(messagetext, 'free') && strContains(messagetext, 'credits') && strContains(messagetext, 'http://')) {
              sendMsgFrom("*** SCAM ALERT ***", callinguser);
            }
          }
        }
      } catch (ex) {} finally {}
    }
    processing_commands = false;
    last_cmd_count = new_length;
    console.log("Finish processing commands... ** SYSTEM FREE **");
    if (monitoring) {
      verifyUserMessageCount();
    }
  }
}

HTML of the IMVU Mobile messages can be found at http://common.snftech.tk/imvu/roomgreet-html-sample.htm


Solution

  • Try changing your function to use each() to loop through each element instead of the loop you have. Once an element has been processed, add a "processed" class to the element so we dont look at them again later. This should be more stable than forcing our logic to keep up with what ones have been processed already.

    Here is a jsFiddle,, throw in the html from your page that actually causes the problem and see if it still occurs

    function verifyCommand() {
      //fixed some logic in here
      if ($(".message-list-item").length > last_cmd_count && !processing_commands) {
        processing_commands = true; // you should set this immediately 
        var new_length = $('.message-list-item').length;
        console.log("Begin processing commands... ** SYSTEM LOCK **");
        console.log('Last command count: '+ last_cmd_count +', New Length: '+new_length);
        var newMessages = $('.message-list-item:not(.processed)'); // get all of the message elements that do not have the class "processed" 
        // loop through each of the message elements
        newMessages.each(function(index, element){
             console.log('Processing new element at index '+index );
             try {
                  var callinguser = $(this).find('.username-text').text().replace("Guest_", "");
                  var messagetext = $(this).find('.message-text').text();
                  $(this).addClass('processed'); // add processed class to the element so we know not to process it again later  
                  if (callinguser != "RoomGreet") {
                    if (messagetext.match(/^\//)) {
                      if (callinguser.match(/IMVU User/)) {
                        die();
                      }
                      processCommand(messagetext.substr(1), callinguser);
                    }
                    else {
                        if (detectFlirt(messagetext)) {
                          if (!isAdmin(callinguser)) {
                            sendMsgRaw('Please do not hit on me, ' + callinguser + '.');
                            logIdiot(callinguser);
                          }
                        }
                        else if (messagetext.match('what is ')) {
                          sendMsgRaw('Please use /solve or /advsolve for math.');
                        }
                        else {
                          if (callinguser != "Nezzle" && !isAdmin(callinguser)) {
                            ident();
                          }
                        }
                      if (strContains(messagetext,"imvu") && strContains(messagetext,"credits") && strContains(messagetext,"http://")) {
                        sendMsgFrom("*** SCAM ALERT ***", callinguser);
                      }
                    }
                  }
             }
             catch (ex) {
                 console.log('caught error');
             } 
             finally {
             }
        });
        last_cmd_count = new_length;
        console.log("Finish processing commands... ** SYSTEM FREE **");
        processing_commands = false;
        if (monitoring) {
          verifyUserMessageCount();
        }
      }
    }