3

Using ES6, Classes, and Aync/Await...

The goal is to have an "Api" class that does async calls with fetch, and returns some data.... but even the basic foundation isn't working.

in the main js these snippet runs, which starts the chain of events:

let api = new Api();
let api_data = api.getLocation();

console.log(api_data);

getLocation method is the following, which would return some response/data. However, that data would theoretically be a fetch call to an API, which is "getTestVariable" for example that waits some time...

class Api {
  getLocation = async () => {
    var response = await this.getTestVariale();
    console.log(response);
    return response;
  }


  getTestVariale = () =>{
    setTimeout(function(){
      console.log("timeout done...");
      return "this is the test variable";
    },2000);
  }
 }

However, 1) the console.log(response) gives "undefined" because its not awaiting... and 2) back in the main js, api_data when logged, is some Promise object rather than the variable response

user10265865
  • 159
  • 2
  • 4
  • 11
  • 2
    Hi! Await doesn't await setTimeout function by design. Await can await any function that will return Promise object. Read this article get more https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function – Drag13 Aug 31 '18 at 15:35
  • 1
    @Drag13 even if I completely remove the setTimeout, and just return the string as is, then api_data is logged out as a Promise. How do I get the actual value of response as a variable – user10265865 Aug 31 '18 at 15:39
  • 1
    You need to work with special object - Promise. If you want to return the string, you need to wrap it with Promise. Check example below. But rather read a bit a bit about promise concept and than go to the async solution – Drag13 Aug 31 '18 at 15:57
  • 1
    As @Drag13 said above. My example provides the immediate solution to your problem but you might want to spend some time reading about Promises and how to handle them in JavaScript. – Peter Van Drunen Aug 31 '18 at 15:59
  • @user10265865 there is no way to 'unwrap' a Promise. Which is why you can only `await` inside of an `async` function, and anything returned from an async function is automatically a Promise. So there is no 'getting the actual response': once you go Promises there's no going back, you have to keep working in Promises. – Jared Smith Aug 31 '18 at 16:04
  • Possible duplicate of [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Jared Smith Aug 31 '18 at 16:06
  • 1
    "*and returns Promise object*" - that's expected. An api that does *asynchronous* things cannot immediately return data, it can only return a promise for it. `async`/`await` syntax doesn't make anything synchronous, it just makes dealing with promises much easier. – Bergi Aug 31 '18 at 16:16

2 Answers2

0

As the comment above states, setTimeout does not return a Promise, so getTestVariable has no return value.

Here's a slightly modified version of your code that will hopefully put you on the right track:

class Api {
  getLocation = async () => {
    var response = await this.getTestVariale();
    console.log(response);
    return response;
  }


  getTestVariale = () => {
      return new Promise((resolve, reject) => {
          if (thereIsError)
              reject(Error('Error message'));
          else 
              resolve({foo: 'bar'});
      }
  }
}

Drop a comment if I need to explain further I'd be happy to.

Peter Van Drunen
  • 543
  • 5
  • 15
0

In getLocation you await for a value that will come from this.getTestVariable. In order for this to work this.getTestVariable must return a Promise; it can be done in two ways - making getTestVariable an async function or explicitly returning a Promise.

Since you're using setTimeout (which is not an async function) you're bound to use Promise. Here you go:

class Api {
  async getLocation() {
    return await this.getTestVariable();
  }

  getTestVariable() {
    return new Promise((res, rej) => {
      setTimeout(() => res('test'), 2000)
    });
  }
}

async function main() {
  let api = new Api;

  console.log('Trying to get the location...');
  console.log('Voila, here it is: ', await api.getLocation());
}

main();

Looks quite ugly but there's no way you can achieve it if you use set timeout.

The main point is in resolution of getTestVariable with value you want it to return.

Quite an important remark: you can mark getTestVariable as an async function, it will ad an extra Promise level, but you still will have the desired result.

lucifer63
  • 784
  • 9
  • 32