0

I've got some code that checks if a user is connected to the internet. It works perfectly, but in the application I have things need to move quickly. In the case that they're connected to a really slow or non-functioning network my statement takes a long time to evaluate to false and really slows things down. If they're connected it retrieves the 1px image in no time at all.

My question is. How can I modify this function to return "false" if it takes more than a second to run the XML request? Can't seem to find an easy way to do this, but I am new to javascript so sorry if I'm missing something obvious.

function doesConnectionExist() {
    var xhr = new XMLHttpRequest();
    var file = "/assets/LuPixel.png";
    var randomNum = Math.round(Math.random() * 10000); 

    xhr.open('HEAD', file + "?rand=" + randomNum, false);

    try {
        xhr.send();
        if (xhr.status >= 200 && xhr.status < 304) {
            return true; //alert("TRUE");
        } else {
            return false; //alert("FALSE");
        }
    } catch (e) {
        return false; //alert("FALSE");
    }
}

UPDATE: thought I needed a little more context.

What I'm trying to do with the above function is test whether a connection exists, and then access a certain URL if it does, if it doesn't, store some info in a local array. As soon as I add timeout however, it breaks the existing functionality.

ANother part that may be complicating things is that I'm actually loading up all survey questions inintially, then using javascript to cycle out which ones display. At the end of the survey it either submits results and refreshes the page (if connected to the internet) or just shows the first question again and continues storing results in the "responses" object (if not connected to the internet) additionally each time a question is clicked it also attempts to use the above doesConnectionExists() function to determine whether to submit results as the javascript transitions to the next question. the questions variable below contains the number of questions left to show

Here is all the javascript from the page.

<script>
//prevents scrolling
document.body.addEventListener('touchmove', function(event) {
  event.preventDefault();
}, false); 

var questions = {{count($questions)}};
var isIOS = ((/iphone|ipad/gi).test(navigator.appVersion));
var myDown = isIOS ? "touchstart" : "mousedown";
var myUp = isIOS ? "touchend" : "mouseup"
var responses = '';

// Hide every div except the first one
$('.survey-container:not(:first)').hide();

$('button').bind(myUp, finish);
//$('button').bind('touchcancel', cancel);

function finish(){
    var answerId = this.id;
    var survey_id = {{$survey->id}};
    var location_id = {{$location_id}};

    //CYCLE THROUGH QUESTIONS (via survey-container)
    // Hide the current div when we click the link
    $(this).parent().parent().next().show();
    $(this).parent().parent().hide();


    responses += answerId+'.'+Math.floor(Date.now() / 1000)+' ';

    //add responses

    if(doesConnectionExist() == true) { //old navigator.onLine == true
        //send response and reset responses
        new Image().src = '/updateresponses?location_id='+location+'&survey_id='+survey_id+'&responses='+responses;
        responses = '';
    }



    //submit and reset responses here
    //reset responses if submitted with: responses = '';

    questions = questions-1; 
    if(questions == 0) {
        $('.survey-container:first').show();
        questions = {{count($questions)}};
        if(doesConnectionExist() == true) {
            $('.darken, .thankyou').show();
            //submit results after a short timeout for thankyou message
            setTimeout(function() {
                new Image().src = '/updateresponses?location_id='+location+'&survey_id='+survey_id+'&responses='+responses;
                location.reload();
                //window.location.assign('/updateresponses?location_id='+location+'&survey_id='+survey_id+'&responses='+responses);
            }, 800);
        } else {
            $('.darken, .thankyou').show();
            setTimeout(function() {
                $('.darken, .thankyou').fadeOut(400);
              }, 1200);
        }
    } else {
        $('.darken, .thankyou').show();
        setTimeout(function() {
            $('.darken, .thankyou').fadeOut(400);
          }, 1200); 
    }


}


function doesConnectionExist() {
    var xhr = new XMLHttpRequest();
    var file = "/assets/lupoll_light.png";
    var randomNum = Math.round(Math.random() * 10000); 


    xhr.open('HEAD', file + "?rand=" + randomNum, false);

    try {
        xhr.send();
        if (xhr.status >= 200 && xhr.status < 304) {
            return true;
        } else {
            return false;
        }
    } catch (e) {
        return false;
    }


}
</script>
Dustin Maxey
  • 125
  • 1
  • 12
  • 1
    `xhr.timeout = 4000;` as stated multiple times on SO, https://stackoverflow.com/questions/1523686/timeout-xmlhttprequest – birdspider Apr 27 '15 at 12:55
  • Don't do this `xhr.open('HEAD', file + "?rand=" + randomNum, false /* Nooooooooooo */);`. Use the onload event instead. That way you can show some sort of progress while you test for a connection – CodingIntrigue Apr 27 '15 at 12:57
  • Thanks, I think these responses are good practice, and sorry for missing the other SO timeout explanations, I wasn't quite searching for the right thing I guess. At any rate. These aren't quite working, setting timeouts as suggested below are breaking the functionality of the page. I may need a little more context. I'll update the original message now. – Dustin Maxey Apr 27 '15 at 14:12

3 Answers3

0

You can use async requests with timeout and abort if time limit exceeded.

var xmlhttp = getXmlHttp()

xmlhttp.open("POST", "/someurl", true); // true - activate async request method

xmlhttp.onreadystatechange=function(){
  if (xmlhttp.readyState != 4) return

  clearTimeout(timeout) // clear timeout on readyState 4

  if (xmlhttp.status == 200) {
      // all ok
      ...
      alert(xmlhttp.responseText);
      ...
  } else {
      handleError(xmlhttp.statusText) // error callback
  }
}

xmlhttp.send("a=5&b=4");
// 10 second timeout
var timeout = setTimeout( function(){ xmlhttp.abort(); handleError("Time over") }, 10000);

function handleError(message) {
  // error callback function
  ...
  alert("error: "+message)
  ...
}
Asgu
  • 712
  • 5
  • 15
0

Add timeout to the xhr object:

xhr.timeout = 1000;
Ole Borgersen
  • 1,094
  • 9
  • 9
0

You can specify the timout for the request:

xhr.timeout = 1000;

Besides setting the timeout, you should make the function asynchronous. That way you can allow a bit longer timeout if you with, and the application will still not be sluggish.

function doesConnectionExist(callback) {
  var xhr = new XMLHttpRequest();
  var file = "/assets/LuPixel.png";
  var randomNum = Math.floor(Math.random() * 10000); 

  xhr.timeout = 1000;

  xhr.onreadystatechange = function() {
    if (xhr.status >= 200 && xhr.status < 304) {
        callback(true);
    } else {
        callback(false);
    }
  };

  xhr.open('HEAD', file + "?rand=" + randomNum, true);
  xhr.send();
}
Guffa
  • 687,336
  • 108
  • 737
  • 1,005