0

I am trying to get a specific piece of data from from a json source. I have declared a global variable and try to update the global variable but it doesn't update correctly. Also, the order in which my debug alerts run is confusing.

<script>

  //global variable
  var latestDoorStatus = "initialized value"; //set value for debugging purposes

  //debug alert which also calls the function
  alert("Alert#1: call getDoorStatus = " + getDoorStatus("***********"));

  function getDoorStatus(public_key) {
    //get data in json form
    var cloud_url = 'https://data.sparkfun.com/output/';
    // JSONP request
    var jsonData = $.ajax({
      url:  cloud_url + public_key + '.json',
      data: {page: 1},
      dataType: 'jsonp',
    }).done(function (results) {
      var latest = results[0];

      //debug alert
      alert("Alert #2:  latestDoorStatus = " + latestDoorStatus);

      //update the global variable
      latestDoorStatus = latest.doorstatus;

      //debug alert
      alert("Alert #3:  latestDoorStatus = " + latestDoorStatus);

      //return the global variable
      return latestDoorStatus;

     });

    alert("Alert #4:  latestDoorStatus = " + latestDoorStatus);
  }

</script>

When I run this in my browser I get the following behaviors:

First I get alert#4 (supposed to run at END of the script) with the initialized value of the global variable

then I get alert#1 as "undefined". This is supposed to be the result of calling the function getDoorStatus which should return an updated value of latestDoorStatus

then I get alert #2 as the initialized value of latestDoorStatus which makes sense since the global variable has not yet been updated

then I get alert #3 with the correct value of latestDoorStatus

The function is supposed to return the variable latestDoorStatus AFTER alert #3 (i.e. after global variable has been updated correctly) so I don't understand why alert #1 (which is supposed to have the returned value) is coming back undefined and why alert#4 which is supposed to run at the very end of the script is running first.

AGSTEIN
  • 43
  • 2
  • 4
  • You should have a look at [How do I return the response from an asynchronous call?](http://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call), I think you have the same problem. – Volune Mar 07 '16 at 07:50

2 Answers2

0

.done() will be called after the response of the AJAX request got received!

1) getDoorStatus() is called from inside alert() at top of code => #4 shown. It does not matter that the function is defined below and not above.

2) alert() at top of code is called & getDoorStatus() does not directly return a value => #1 shown with undefined.

3) AJAX response returned, .done() function gets called => #2 and #3 are shown.

RhinoDevel
  • 712
  • 1
  • 12
  • 25
0

You are calling $.ajax asynchronously, and passing a callback function to done.

function makeRequest() {
  $.ajax({ // An async Ajax call.
    url:  cloud_url + public_key + '.json',
    data: {page: 1},
    dataType: 'jsonp',
  }).done(function (results) {
    // this code is executed only after the request to cloud_url is finished.
    console.log("I print second.");
  });

  console.log("I print first.");
}

The callback is called when the request is finished, and when depends entirely on how long the request to https://data.sparkfun.com/output/ takes. So the code after your Ajax call is executed immediately, we're not waiting for the http request to finish.

Your function getDoorStatus returns nothing, but your callback passed to done does. The thing you need to know is that you can't return anything from asynchronously executed functions. Well, you can return, but there will be nothing there to use the returned value.

So instead, do the things you want to do with the returned data from https://data.sparkfun.com/output/ in the callback passed to done.

function getDoorStatus(public_key) {
  //get data in json form
  var cloud_url = 'https://data.sparkfun.com/output/';
  // JSONP request
  var jsonData = $.ajax({
    url:  cloud_url + public_key + '.json',
    data: {page: 1},
    dataType: 'jsonp',
  }).done(function (results) {
    // latestDoorStatus = results[0]; // Not a good practice.
    // Instead:
    showDoorStatus(results[0]);
  });   
}


function showDoorStatus(status) {
  document.getElementById("door-status").innerText = status;
  // Or something like this.
}

getDoorStatus("***********");

And somewhere in your HTML:

<p id="door-status"></p>
jeoj
  • 633
  • 6
  • 9
  • Thank you, this suggestion worked. The thing I still don't understand is that I placed the "return" in the area that you indicated // this code is executed only after the request to cloud_url is finished so it should not have returned a value until after the cloud request had completed so when I called getDoorStatus("***********")); why didn't it give me a valid response (i.e. even if the ajax call was asynchronous the return should have waited until completion and Alert #1 should have had good data)? – AGSTEIN Mar 08 '16 at 05:46
  • You can not return from the callback function that you pass to done, because there is no guarantee when this function will be executed; the function is executed when the request is finished, and at that point, most of the code after your Ajax call has probably already been executed. The behaviour you described (or wanted?) only works on synchronous calls – that is, execution will be halted until the request is finished. Your assumption "even if the ajax call was asynchronous the return should have waited until completion and Alert #1 should have had good data" – simply doesn't hold true. – jeoj Mar 08 '16 at 07:25
  • If the answer helped you get your problem solved, you can accept the answer, by the way :) – jeoj Mar 08 '16 at 07:27