initLogs 4: Why am I getting [object Promise] when calling async function in JavaScript

Published: 17 February, 2022 | 4 mins(s) read | Tags: #programming #javascript | Series: initLogs


Posts from "InitLogs" series:

When I learnt about promises and asynchronous coding. The biggest time consumer was when I tried calling an asynchronous function inside a normal function (synchronous code). I was hoping to use the asynchronous function to get the promises which had the values I was looking for. But what I got was [object Promise]. The asynchronous function was working fine. But when I called the async function inside a normal function it would return [object Promise]. So no promises!

A gif where a woman tells a man no promises.

Why?

You are getting [object Promise] as value because you are calling an asynchronous function inside a synchronous code. This means the synchronous code runs line by line giving no room for asynchronous code to wait and give a response (the promise). You have to wrap an asynchronous function around the asynchronous function you are calling to get the desired result.

An image with an input field and a button.

Initial state of the webpage which have an input field and a button

In the below code, we are creating a function which returns a promise. The below callOpenWeather() function uses fetch API to call the OpenWeather api so that we can get a value called feels_like. This feels_like is a numerical value.


//Async function to fetch the weather info
// using OpenWeather API
const callOpenWeather = async (url) => {
	// Try part when successful return of promise
    try {
		// Calls the API url, parses to JSON, returns
		// feels_like value which is in Farenheit for a particular area.
        let callJson = await fetch(url, {mode: 'cors',});
        let loadJson = await callJson.json();
		return loadJson.main.feels_like;
    
	// Catch part if promise returns an error
	} catch(error) {
        return error;
    }
}

Incorrect way: Asynchronous function inside a synchronous code

Now let’s write a function which will interact with the above callOpenWeather(). The below code won’t work. When you need to call callOpenWeather() function which returns a promise, you cannot call it inside a synchronous code as shown below. It will return [object Promise] as response.

// DOM function to get the data from input and
// use checkWeather function to get the data displayed.
const displayWeather = () => {
    
    const submitButton = document.getElementById('button');
    const inputValue = document.getElementById('search');
    const infoBox = document.getElementById('info-box');

    submitButton.addEventListener('click', () => {
        
        infoBox.style.display = 'grid';
        infoBox.innerText = callOpenWeather(`http://api.openweathermap.org/data/2.5/weather?q=${inputValue.value}&APPID=${apiKey}`); // Use an api key of openweather instead of ${apiKey} to make this code work.
        infoBox.style.boxShadow = '0 0 2px 0 #d3d3d3';    

    });
}

displayWeather();

An image with an input field and a button which displays [object Promise] as response.

The function returns [object Promise] instead of returning the expected value.

This is because when infoBox.innerText calls the callOpenWeather() function, the displayWeather() function is still a normal synchronous function. This means the lines are executed line by line and does not wait for the value from callOpenWeather() which is an asynchronous function. To call callOpenWeather() and get the value (a promise), make it asynchronous. You can do this by wrapping callOpenWeather() inside an async function using async/await method as shown below. This will make an api call to OpenWeather API and wait for the result so that the result can be set and displayed in infoBox.innerText.

Correct way: Asynchronous function wrapped with an asynchronous function

We are wrapping an async function with the eventlistener for the click event. This will let callOpenWeather() function to run properly and wait until it returns a response as provided by the Open Weather API. The below solution uses async/await method. You can see the usage of await keyword which waits for a response from the callOpenWeather() function and returns a promise.


// DOM function to get the data from input and
// use checkWeather function to get the data displayed.
const displayWeather = () => {
    
    const submitButton = document.getElementById('button');
    const inputValue = document.getElementById('search');
    const infoBox = document.getElementById('info-box');

    submitButton.addEventListener('click', async () => {
        
        infoBox.style.display = 'grid';
        infoBox.innerText = await callOpenWeather(`http://api.openweathermap.org/data/2.5/weather?q=${inputValue.value}&APPID=${apiKey}`); // Use an api key of openweather instead of ${apiKey} to make this code work.
        infoBox.style.boxShadow = '0 0 2px 0 #d3d3d3'; 

    });
}

displayWeather();

An image with an input field and a button which displays expected value as response.

The function returns the expected numerical value

This is how you could get the value from your asynchronous code when you are stuck with [object Promise] as your output. This is one of those scenarios where if you think about it, it makes total sense. But our synchronous mind could find it tricky.


Found an error? Have feedback on my writing? DM me on Twitter @unsungNovelty.

← New year resolutions can be a useful & necessary first step Takeaways from 2021 →