axios i kilka obietnic...

0

Nie wiem czy tytuł tematu jest wstanie nakierować na mój problem ale spróbuję wytłumaczyć.
Mam dwie funkcje asynchroniczne getWeather() i getAdvice().
Pierwsza wysyła żądanie i pozyskuje informacje pogodowe o mieście. Druga funkcja wysyła żądanie i otrzymuje w odpowiedzi jakiś życiowy cytat :P
Można powiedzieć, że wszystko działa ok ale nie do końca, bo chciałbym aby w tym samym czasie otrzymać odpowiedź (resolve?) od dwóch obietnic. Czy jest jakaś możliwość "wyliczenia" aby np. pierwsza obietnica czekała, aż druga otrzyma wynik?

Tutaj kod źródłowy stronki: https://github.com/KrwawyOrk/Weather-App/blob/master/src/components/WeatherApp.vue

2

Użyj Promise.all()

czyli jakoś tak:

async function getData() {
      await Promise.all([
        axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${inputCity.value}&appid=${weatherApiKey}&units=metric`),
        axios.get("https://api.adviceslip.com/advice")
      ]).then(([weatherResponse, adviceResponse]) => {
        // weather
        ((response) => {
          console.log(response.data);

          cityFound.value = false;

          const {
              data: { main, name, weather, sys },
          } = response;

          const ref = weatherData.value;
          ref.city = name;
          ref.country = sys.country;
          ref.temperature = parseInt(main.temp);
          ref.temperatureFellsLike = parseInt(main.feels_like);
          ref.temperatureMin = main.temp_min;
          ref.temperatureMax = main.temp_max;
          ref.description = weather[0].description;
          ref.iconUrl = `https://openweathermap.org/img/w/${weather[0].icon}.png`;
        })(weatherResponse)

        // advice
        ((response) => {
          const {
            data: {
              slip: { advice },
            },
          } = response;
          adviceForTheDay.value = advice;
        })(adviceResponse)
      }).finally(() => {
          inputCity.value = "";
          cityFound.value = true;
      });
    }

tylko teraz w @click="getWeather" musisz dać @click="getData".

0

No ciekawe rozwiązanie, zaraz do niego powrócę. Dzięki, za odpowiedź.
Żeby nikt nie myślał, że jestem leniem to troszkę sam coś pokombinowałem:

function fetchData() {
      const promise1 = axios.get(`https://api.openweathermap.org/data/2.5/weather?q=Opole&appid=${weatherApiKey}&units=metric`);
      const promise2 = axios.get("https://api.adviceslip.com/advice");

      Promise.all([promise1, promise2]).then(response => console.log(response));
    }
1

Można też tak:

async function getData() {
   const weatherResponse = await axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${inputCity.value}&appid=${weatherApiKey}&units=metric`);  
   const adviceResponse = await axios.get("https://api.adviceslip.com/advice");
...

Po komentarzu @m31 zmieniam wersję na:

async function getData() {
  const [weatherResponse, adviceResponse] = await Promise.all(
    axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${inputCity.value}&appid=${weatherApiKey}&units=metric`),
    axios.get("https://api.adviceslip.com/advice"),
  );
...
0

Zastanawia mnie ten kawałek kodu zamykającego instrukcję: })(weatherResponse), jeszcze nie spotkałem się z takim zapisem w JS, czy jest to coś na podobieństwo rzutowania w C++?

1

To jest utworzenie i wywołanie funkcji JS (blok z funkcją)(wywołanie) np.:

(() => console.log(123)) // sama definicja
(() => console.log(123))(); // definicja + wywołanie
((a) => console.log(a))(123) // wywołanie z argumentem

Jednak jak na moje oko zupełnie niepotrzebne w powyższym kodzie, tylko komplikuje kod.

0

Chyba zdecyduję się na taką wersję:

async function fetchData() {
      const promise1 = await axios.get(
        `https://api.openweathermap.org/data/2.5/weather?q=Opole&appid=${weatherApiKey}&units=metric`
      );
      const promise2 = await axios.get("https://api.adviceslip.com/advice");

      Promise.all([promise1, promise2]).then((response) => {
        console.log(response[0]);

        console.log(response[1].data.slip.advice);
      });
    }

Coś takiego, to tylko próbka kodu.

0
Markuz napisał(a):

To jest utworzenie i wywołanie funkcji JS (blok z funkcją)(wywołanie) np.:

(() => console.log(123)) // sama definicja
(() => console.log(123))(); // definicja + wywołanie
((a) => console.log(a))(123) // wywołanie z argumentem

Jednak jak na moje oko zupełnie niepotrzebne w powyższym kodzie, tylko komplikuje kod.

IIFE (Immediately Invoked Function Expression) było po, bo nie chciało mi się zmieniać nazw zmiennych. Obie funkcje getWeather i getAdvice miały zmienną (właściwie to stałą) data. Po scaleniu tych dwóch funkcji w jedną, ta zmienna by kolidowała.

Można było to przerobić prościej np. tak

async function getData() {
      await Promise.all([
        axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${inputCity.value}&appid=${weatherApiKey}&units=metric`),
        axios.get("https://api.adviceslip.com/advice")
      ]).then(([weatherResponse, adviceResponse]) => {
        // weather
          console.log(weatherResponse.data);
          cityFound.value = false;

          const {
              data: { main, name, weather, sys },
          } = weatherResponse;

          const ref = weatherData.value;
          ref.city = name;
          ref.country = sys.country;
          ref.temperature = parseInt(main.temp);
          ref.temperatureFellsLike = parseInt(main.feels_like);
          ref.temperatureMin = main.temp_min;
          ref.temperatureMax = main.temp_max;
          ref.description = weather[0].description;
          ref.iconUrl = `https://openweathermap.org/img/w/${weather[0].icon}.png`;

        // advice
        adviceForTheDay.value = adviceResponse.data.slip.advice;
      }).finally(() => {
          inputCity.value = "";
          cityFound.value = true;
      });
    }

Ale szybciej dla mnie było po prostu skopiować obie funkcje i je domknąć. Można też było je zamknąć w osobnych blokach {}. I przypisać w każdym np. const response = weatherResponse

Krwawy Ork napisał(a):

Chyba zdecyduję się na taką wersję:

async function fetchData() {
      const promise1 = await axios.get(
        `https://api.openweathermap.org/data/2.5/weather?q=Opole&appid=${weatherApiKey}&units=metric`
      );
      const promise2 = await axios.get("https://api.adviceslip.com/advice");

      Promise.all([promise1, promise2]).then((response) => {
        console.log(response[0]);

        console.log(response[1].data.slip.advice);
      });
    }

Coś takiego, to tylko próbka kodu.

Tutaj wywołujesz dwie funkcje sekwencyjnie. Jak już coś to:

async function fetchData() {
      const promise1 = axios.get(
        `https://api.openweathermap.org/data/2.5/weather?q=Opole&appid=${weatherApiKey}&units=metric`
      );
      const promise2 = axios.get("https://api.adviceslip.com/advice");

      Promise.all([promise1, promise2]).then((response) => {
        console.log(response[0]);

        console.log(response[1].data.slip.advice);
      });
    }
0

ok, dziękuję wszystkim za pomoc. Troszkę przerobiłem funkcję i wszystko działa ok. Wcześniej div, który wyświetlał pogodę i cytat kurczył się albo zwężał ponieważ cytat z poradą "pojawiał" się ok. 0.2s później. Jeszcze zastanawiałem czy nie można jakoś skrócić tych funkcji i np. pozyskanie pogody i cytatu rozbić w osobne funkcje, żeby getData nie była aż tak duża

[b]edit:[/b] trochę inne pytanie: zastanawiam się czy jest sens sprawdzać warunki w divach, bo przy każdym divie sprawdzam czy faktycznie wartość istnieje: np. v-

<h1
            v-if="weatherData.city && weatherData.country"
            class="text-3xl font-bold text-center"
          >

Mam chyba przyzwyczajenie z C++ jeszcze....

async function getData() {
      const weatherApiUrl = `https://api.openweathermap.org/data/2.5/weather?q=${inputCity.value}&appid=${weatherApiKey}&units=metric`;
      const adviceApiUrl = "https://api.adviceslip.com/advice";

      await Promise.all([axios.get(weatherApiUrl), axios.get(adviceApiUrl)])
        .then((response) => {
          cityFound.value = false;

          //Weather
          const {
            data: { main, name, weather, sys },
          } = response[0];

          const ref = weatherData.value;
          ref.city = name;
          ref.country = sys.country;
          ref.temperature = parseInt(main.temp);
          ref.temperatureFellsLike = parseInt(main.feels_like);
          ref.temperatureMin = main.temp_min;
          ref.temperatureMax = main.temp_max;
          ref.description = weather[0].description;
          ref.iconUrl = `https://openweathermap.org/img/w/${weather[0].icon}.png`;

          //Advice
          const {
            data: {
              slip: { advice },
            },
          } = response[1];

          adviceForTheDay.value = advice;
        })
        .finally(() => {
          inputCity.value = "";
          cityFound.value = true;
        });
    }

1 użytkowników online, w tym zalogowanych: 0, gości: 1