Alexander Prisazhny
Alexander Prisazhny

Reputation: 154

How to obtain [[PromiseValue]]'s content if .then() doesn't work out?

The situation is: I have an array of cities, function getCityForecast that fetches forecast for each of them and returns the received converted data into a needed format. I need to save them into the array and save this array in state of the component.

this.state = {
      cities: [
        'Санкт-Петербург',
        'Москва',
        'Казань',
        'Самара',
        'Красноярск',
        'Чита',
        'Челябинск',
        'Оренбург',
        'Ростов-на-Дону',
        'Орск'
      ],

      cityObjects: []
    };

    this.getCityForecast = this.getCityForecast.bind(this);
    this.renderCities = this.renderCities.bind(this);
}

getForecastData = async (cityKey, cityName) => {
    const apiKey = 'ExAmPlEkEy';
    const forecastUri = 'http://dataservice.accuweather.com/forecasts/v1/daily/1day/';
    const uriToFetch = `${forecastUri}${cityKey}?language=ru&metric=true&details=true&apikey=${apiKey}`;
    try {
      let response = await fetch(uriToFetch);
      if(response.ok) {
        let jsonResponse = await response.json(); // Converts into JSON
        if (jsonResponse.DailyForecasts) {
          let cityData = jsonResponse.DailyForecasts.map(forecast => ({ //Data converted here into a convenient object
            icon: forecast.Day.Icon,
            iconPhrase: forecast.Day.IconPhrase,
            tempValue: forecast.Temperature.Maximum.Value,
            tempUnit: forecast.Temperature.Maximum.Unit,
            cityKey: cityKey,
            cityName: cityName
          })   
        );

        let renderCity = cityData.map(city => ( // Presented in React.js manner
              <div
                className="weather"
                key={city.cityKey}>
                <h1>{city.cityName}</h1>
                <img
                  src={`http://apidev.accuweather.com/developers/Media/Default/WeatherIcons/${city.icon}-s.png`}
                  alt={city.iconPhrase}
                  className="weathericon" />
                <h2>{`Температура: ${city.tempValue}°${city.tempUnit}`}</h2>
              </div>
            )
          );

          return renderCity; // Retuns a formatted city forecast
        } else {
          return [];
        }
      }
      throw new Error('Forecast request failed!');
    } catch (error) {
      console.log(error);
    }
  }

renderCities = () => { // applies this.getCityForecast() to the array of city names
    if(this.state.cities) {
      const cityObj = Promise.all(this.state.cities
        .map(city => this.getCityForecast(city)))
          .then(promiseResp => (promiseResp)) // CASE ONE
          /*.then(val => (val))*/ // CASE TWO <-- Not the above promise's value
          .catch(e => {console.log(e)});
      console.log(cityObj); // Save response to this.cityObjects
    }
  }

So the issue is that in CASE ONE it returns:

_proto__: Promise
[[PromiseStatus]]: "resolved"
[[PromiseValue]]: Array(2) // <-- I need this content
  0: [{…}]
  1:  [{…}]
  length: 2
  __proto__:  Array(0)

And in CASE TWO I've got:

__proto__: Promise
[[PromiseStatus]]: "pending"
[[PromiseValue]]: undefined

How do I get CASE ONE's [[PromiseValue]] content?

Upvotes: 0

Views: 4656

Answers (1)

Michał Perłakowski
Michał Perłakowski

Reputation: 92501

You should make renderCities an async function and await the promise:

renderCities = async () => { // applies this.getCityForecast() to the array of city names
    if(this.state.cities) {
      const cityObj = await Promise.all(this.state.cities
        .map(city => this.getCityForecast(city)))
          .catch(e => {console.log(e)});
      console.log(cityObj); // Save response to this.cityObjects
    }
  }

.then(promiseResp => (promiseResp)) or .then(val => (val)) doesn't really do anything – you're just mapping the value inside the promise to itself.

See also How to access the value of a promise?

Upvotes: 1

Related Questions