Il problema del promise hell in JavaScript

Già sapete che le promise sono state create per risolvere il problema del callback hell. Tuttavia, col tempo si è scoperto che le promise sono anch'esse in grado di generare codice complesso. Questo problema per analogia è stato chiamato promise hell.

Analizziamo questo problema con esempi di codice. Supponiamo di avere una funzione getSmth, che riceve un parametro e restituisce un risultato in base a questo parametro:

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

In questo caso stiamo simulando un'operazione utile (ad esempio, il recupero di dati da un server). Come simulazione, passiamo semplicamente un numero come parametro e dopo un secondo restituiamo il quadrato di questo numero.

Utilizziamo ora la nostra funzione getSmth all'interno di un'altra funzione:

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

func();

Primo problema

Multiple costrutti then che si susseguono rendono difficile la comprensione del codice:

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

func();

Secondo problema

Esiste un problema anche di altro tipo. Supponiamo ora di voler utilizzare la nostra funzione due volte, per poi sommare i risultati. Come risultato otterremo questo codice:

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

func();

Già ricorda il callback hell, vero? Aggiungiamo un'altra chiamata alla funzione - il codice diventerà ancora peggiore:

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

func();

Si potrebbe, certamente, utilizzare Promise.all:

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

func();

Tuttavia, abbiamo ottenuto la stessa cosa? No! Nel primo caso ogni nuova funzione attende il completamento della promise precedente, mentre nel secondo caso - tutte le promise vengono eseguite contemporaneamente. Questa differenza sarà sostanziale nel caso in cui vogliamo passare il risultato di una funzione alla successiva:

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

func();