0

Im a newbie javascript developper and this is my first time as a stackoverflow user but I have got valuable information from reading posts here.

I need to load a file but the code should wait because of the asynchronous nature of it. I thought a Promise might work and it is almost working but it's just still not waiting (synchronous) for the file to load. It does however wait at the end when there is no file. It should be the other way around it should wait until the file is loaded. then continue and run the next function which needs the data.

Can anyone tell me why my promise is not working? Should I even be using a promise for this or a callback?

Here is the code:

// ...

var p = new Promise(function (resolve, reject) {
    let x = getTheData(); // async data but program don’t wait.
    if (!x) { //if no data I want to wait?
        resolve('success');
        console.log('success');
    }else {
        reject('failure');
        console.log('failure');
    }
});

p.then(function () {
    let y = getNewFunctionThatNeedsTheAboveDataToWork();
    res.send('y is not working ' + y);
}).catch(function(){
    console.log('error');
});

return p;

I'm completely lost, any help would be graceful.

pirs
  • 2,410
  • 2
  • 18
  • 25
  • 2
    `data taking forever to come but program won’t wait.` ... so, you're saying that `getTheData` is asynchronous? But you're using the synchronous return value to check? more info needed about `getTheData` function ... what does it return? (a promise? if so, then `var p = getTheData()` would be enough to fix your little issue) - another thing to note: p will resolve to `success` or reject to `failure` ... so, there's no "data" available for `getNewFunctionThatNeedsTheAboveDataToWork` as you've not received any data from `getTheData` – Jaromanda X Nov 23 '17 at 03:07
  • 2
    What is the code of `getTheData()` so ? – pirs Nov 23 '17 at 03:15
  • You call an asynchronous function in a synchronous way, don't expect it will work like this.. please share more code and we ll help you for sure. – pirs Nov 23 '17 at 03:20
  • The getTheData() calls out to an api. and will give me json. It looks like this function getTheData(){ data = (calls to an api)} This is taking all the time. How can I get this to stop here. Once this function gets the data I want the next function getNewFunctionThatNeedsTheAboveDataToWork() { (takestheabovedata) and computes the temperature of different cities. but it can't do that without the cities – baryjones23saturn Nov 23 '17 at 03:49
  • @baryjones23saturn How does the `getTheData` function "give you json"? Surely it doesn't return it, as that would mean it's *not* asynchronous. So how does it notify you that the data is ready? – Bergi Nov 23 '17 at 04:26
  • That's my question, how do I get it to know my data is ready. – baryjones23saturn Nov 23 '17 at 04:45
  • That's my question, how do I get it to know my data is ready. Right now it just goes to the next line I have funtion1 (needs to get data (this takes time) ) the very next function on the next line needs that data to work but doesn't have it. It keeps getting undefined because the data isn't back from the api yet. If it was synchronous I wouldn't have a problem, I'm looking for the javascript design pattern to fix this. How can I wait for the file to load so the next function can use the data? I thought promise or callback might work – baryjones23saturn Nov 23 '17 at 04:52
  • Based on the OP's comments that what they really need to know is how to code `getTheData()` properly to communicate back asynchronous results, I've marked it a duplicate of [How to return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-asynchronous-call/14220323#14220323) – jfriend00 Nov 23 '17 at 05:54

1 Answers1

0

The problem here is that getData is asynchronous, so you need some way to know when it is done. That means that getData either needs to return a promise (the newer way), or accept a callback as an argument (the older way). Here is an example of how getData could be used with promises to fetch data via web call (this would be syntatically much simpler with jQuery.get, but let's stick to pure javascript for the moment):

var getData = function() {
  var p = new Promise(function (resolve, reject) {
    var xhr = new XMLHttpRequest();
    xhr.addEventListener("readystatechange", function () {
      if (this.readyState === 4 && this.status != 200) {
          console.log('Data request returned an error');
          reject('failure');
      } else if (this.readyState === 4 && this.status === 200) {
          resolve(this.responseText);
      }
    });
    xhr.open("GET", "https://httpbin.org/get", true); // true = async
    xhr.send();
  })
  return(p)
}

Then we can use this function like this:

getData().then(function(d) {
  console.log(d);
  // do something useful with d
})

Alternatively, you can accomplish the same thing with a callback:

var getData2 = function (cb) {
  var xhr = new XMLHttpRequest();
  xhr.addEventListener("readystatechange", function () {
    if (this.readyState === 4 && this.status != 200) {
        console.log('Data request returned an error');
        cb(null, "error");
    } else if (this.readyState === 4 && this.status === 200) {
        cb(this.responseText);
    }
  });
  xhr.open("GET", "https://httpbin.org/get", true);
  xhr.send();
}

getData2(function(d, e) {
  if(e) {
    console.log("oops.  there was an error: ", e);
  } else {
    console.log(d);
  }
})

Finally, if the getData function is coming from somewhere else and you cannot change it, you can convert it from a callback style function to a promise style function. Here is one way:

var promiseMe = new Promise(function (resolve, reject) {
  getData2(function(d, e) {
    if(e) {
      reject(e)
    } else {
      resolve(d)
    }
  })
})

promiseMe.then(function(d) {
  console.log(d)
})

EDIT

The above works in the browser. Here is one way to do it in node:

http = require('http');

var getData = function() {
  var p = new Promise(function (resolve, reject) {
    var data = '';
    http.get('http://httpbin.org/get', function(res) {
        res.on('data', (chunk) => {
            data += chunk;
        });

        res.on('end', () => {
            resolve(data);
        });
    })
  })
  return(p)
}
getData().then(function(d) {
    console.log(d)
})

I hope these examples start to clear things up.

Eric
  • 1,691
  • 16
  • 24
  • Eric thank you very much. I think I am on to somethig with your answer. I really appreciate your help. But I have a question, I get a referenceError, XMLHttoRequest is not defined or XMLHTTP request is not a constructor. I have tried adding the xmlhttp as var XMLHttpRequest = require("xmlhttprequest"); but that is not working either. I wrote this in express. I assume the XMLHttp won't work with plain html? – baryjones23saturn Nov 23 '17 at 13:50
  • @baryjones23saturn XMLHttpRequest should be natively supported by the browser. In your question you mention XMLHttoRequest (note the 'o' instead of the 'p') Was that just a typo or do you actually have that in your code? For node.js, you can npm install xmlhttprequest and then require it, but the preferred way in node is to use the http package or similar. See revised answer above. – Eric Nov 23 '17 at 17:04
  • Eric I went ahead and just tried an example in plain html and javascript using the fetch api, I like it alot I found an example on their site and worked through it and I had it working fine from my computer. Once I switched the code to express I got a error in my json file SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data. very tough to find. My question is why would this code work fine in plain html: – baryjones23saturn Nov 27 '17 at 16:20
  • @baryjones23saturn that typically just means the request did not return valid JSON, and probably returned some error. You can return the raw response, or dump it to stdout with console.log to see what is actually returned. That should shed some light on what the error is. – Eric Nov 27 '17 at 16:27
  • how are people posting their code without running out of characters? – baryjones23saturn Nov 27 '17 at 16:27
  • only short snippets can go in comments. you may need to ask a new question related to this new aspect of the problem to post more code. – Eric Nov 27 '17 at 16:29
  • https://stackoverflow.com/questions/47516239/syntaxerror-json-parse-unexpected-character-at-line-1-column-1-of-the-json-dat – baryjones23saturn Nov 27 '17 at 17:05