Problem promise hell w JavaScript

Wiesz już, że promisy zostały stworzone, aby rozwiązać problem callback hell. Jednak z czasem okazało się, że promisy również mogą generować skomplikowany kod. Ten problem przez analogię został nazwany promise hell.

Przyjrzyjmy się temu problemowi na przykładach kodu. Załóżmy, że mamy funkcję getSmth, która pobiera parametr i zwraca wynik w zależności od tego parametru:

javascriptfunction getSmth(num) {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(num * num), 1000)
  });
}

W tym przypadku symulujemy pewną użyteczną operację (na przykład pobieranie danych z serwera). Jako symulację po prostu przekazujemy parametrem liczbę i po sekundzie zwracamy kwadrat tej liczby.

Skorzystajmy teraz z naszej funkcji getSmth wewnątrz innej funkcji:

javascriptfunction func() {
  getSmth(2).then(res => {
    console.log(res); // wypisze 4
  });
}

func();

Pierwszy problem

Wiele następujących po sobie konstrukcji then utrudnia zrozumienie kodu:

javascriptfunction func(){
  getSmth(2).then(res1 => {
    // robimy coś
  }).then(res2 => {
    // robimy coś
  }).then(res3 => {
    // robimy coś
  }).then(res4 => {
    // robimy coś
  }).then(res5 => {
    // robimy coś
  }).then(res6 => {
    // robimy coś
  });
}

func();

Drugi problem

Istnieje też problem innego rodzaju. Załóżmy teraz, że chcemy skorzystać z naszej funkcji dwa razy, a następnie zsumować wyniki. W rezultacie otrzymamy taki kod:

javascriptfunction func() {
  getSmth(2).then(res1 => {
    getSmth(3).then(res2 => {
      console.log(res1 + res2); // wypisze 13
    });
  });
}

func();

Już przypomina callback hell, prawda? Dodajmy jeszcze jedno wywołanie funkcji - kod stanie się jeszcze gorszy:

javascriptfunction func() {
  getSmth(2).then(res1 => {
    getSmth(3).then(res2 => {
      getSmth(4).then(res3 => {
        console.log(res1 + res2 + res3);
      });
    });
  });
}

func();

Można oczywiście skorzystać z Promise.all:

javascriptfunction func() {
  Promise.all([getSmth(2), getSmth(3), getSmth(4)]).then(res => {
    console.log(res[0] + res[1] + res[2]);
  });
}

func();

Jednak czy otrzymaliśmy to samo? Nie! W pierwszym przypadku każda nowa funkcja oczekuje zakończenia poprzedniego promisa, a w drugim przypadku - wszystkie promisy wykonywane są jednocześnie. Ta różnica będzie istotna w przypadku, gdy do następnej funkcji będziemy chcieli przekazać wynik poprzedniej:

javascriptfunction func() {
  getSmth(2).then(res1 => {
    getSmth(res1).then(res2 => {
      getSmth(res2).then(res3 => {
        console.log(res3);
      });
    });
  });
}

func();