0

I am unable to callback async function inside of another async function. I am receiving this in the console:

Promise {<pending>}
__proto__: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: Object

script.js:127 TypeError: Cannot read property 'aWeatherObjProperty' of undefined
  at callForecastAPI (script.js:121)
  at HTMLInputElement.<anonymous> (script.js:138)

Here is my JavaScript code:

function processSearchInput(searchInput) {
  // does some math. No waiting required.
  return processedSearchInput;
}
// processedSearchInput is an object

// Take processedSearchInput and call OpenWeather API
async function callWeatherAPI(processedSearchInput) {
  const response = await fetch(`calling API`, { mode: 'cors' });
  const weather = await response.json();
  return weather;
}
// weather is an object

// Call OpenWeather Forecast API and return weatherForecast object
async function callForecastAPI(weatherObj) {
  const response = await fetch(`calling API`);
  const weatherForecast = await response.json();
  return weatherForecast;
}

callForecastAPI(callWeatherAPI(processSearchInput(searchInput)));

I am certain weather object is being returned by callWeatherAPI as I can console.log it right before the return and can return it right before the fetch in callForecasrAPI. Thank you in advance for any advice.

captaincustard
  • 321
  • 2
  • 12
  • Have you tried putting the await keyword inside your calForecastApi function? `async function callForecastAPI(weatherObj) { await weatherObj; const response = await fetch('calling API'); const weatherForecast = await response.json(); return weatherForecast; }` – Hector Marin Jul 14 '21 at 01:17
  • @HectorMarin: You're correct. I am commenting on someone's answer trying to clarify why that is the case. If you could chime in, I'd appreciate it. – captaincustard Jul 14 '21 at 03:28
  • @captaincustard async-await is just syntactic sugar for promises, a nicer way to code them. It does not magically make asynchronous processes run as if they're synchronous, since this would require either the entire thread that JS is running on to be blocked while waiting for the result... or some form of time travel. – Lennholm Jul 14 '21 at 11:25

1 Answers1

1

If you're trying to call callWeatherAPI() and pass the actual result of that to another function, then you have to await it. It is an async function and ALL async functions return a promise. The return value inside your async function becomes the resolved value of the promise. So, to get the value from the promise, you can use await or .then().

callForecastAPI(await callWeatherAPI(processSearchInput(searchInput)));

This, of course, means that this code itself will need to be inside an async function so you can use await.

For more on how an async function always return a promise see Why do I need to await an async function when it is not supposedly returning a Promise?.

And, callForecastAPI() is also async and also returns a promise so to get the actual Forecast result, you will need to use await or .then() on that too.

const forecast = await callForecastAPI(await callWeatherAPI(processSearchInput(searchInput)));

Or, perhaps it's clearer with an intermediate variable:

const weather = await callWeatherAPI(processSearchInput(searchInput));
const forecast = await callForecastAPI(weather);
console.log(forecast);
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Buy does not callWeatherAPI itself wait for its own fetch and json() before it can return anything? Why do I have to ask another function to wait for it, if it waits for itself? Based on that answer you provided, does that mean 'weather' even though it was already assigned to the 'awaited' results from response.json(), still a mmm a promise and still needs to resolved?! So, inside the function body, I got 2 things to wait for (fetch and .json) and then I got to wait for the function itself?! – captaincustard Jul 14 '21 at 03:27
  • @captaincustard - please read the other answer I linked to in my answer. It has to do with how async functions work and that is explained in that other post. And, you need to understand that. It's also explained in my first paragraph of this answer. Async functions ALL return a promise. – jfriend00 Jul 14 '21 at 03:42
  • @captaincustard - To reiterate what is in the other answer I linked above, when an `async` function hits the first `await` inside the function, it immediately suspends execution of that function and then returns an unresolved promise. The caller just gets the unresolved promise and continues to execute. Sometime later, when the promise you were awaiting resolves, then the function will continue to execute and when it hits a `return` statement, the value you return will become the resolved value of the promise that was previously returned. – jfriend00 Jul 14 '21 at 04:39
  • @captaincustard - So, `return x` in an `async` function is really "set resolved value of the promise we already returned to `x`" and resolve that promise. The `async` function long ago returned the promise. – jfriend00 Jul 14 '21 at 04:39
  • Thank you very much. I get it know. But, if you could clarify your statement: "and then returns an unresolved promise"? The message I get says "fulfilled." I thought a promise cannot get fulfilled without being resolved. – captaincustard Jul 14 '21 at 13:15
  • @captaincustard - Are you running this as a single script from the OS command line or are you running it line by line in the console? – jfriend00 Jul 14 '21 at 16:06
  • I'm running it in Chrome. – captaincustard Jul 14 '21 at 19:31
  • @captaincustard - I don't know why the error reads as it does. Perhaps, it is fulfilled by the time the object gets logged in the console (which is often delayed from real time). I'd have to be able to debug it myself and instrument it to explain any further, but what you have in your question is not runnable by us. – jfriend00 Jul 14 '21 at 23:04