Problem promise hell v JavaScriptu

Že veste, da so bili promisi ustvarjeni za rešitev problema callback hell. Vendar se je sčasoma izkazalo, da lahko tudi promisi povzročijo zapleteno kodo. Ta problem je bil po analogiji imenovan promise hell.

Oglejmo si ta problem na primerih kode. Recimo, da imamo funkcijo getSmth, ki prejme parameter in vrne rezultat odvisno od tega parametra:

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

V tem primeru posnemamo neko uporabno operacijo (na primer, pridobivanje podatkov s strežnika). Kot simulacijo preprosto parameter podamo število in čez sekundo vrnemo kvadrat tega števila.

Zdaj pa uporabimo našo funkcijo getSmth znotraj druge funkcije:

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

func();

Prva težava

Številne konstrukcije then, ki sledijo ena za drugo, otežujejo razumevanje kode:

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

func();

Druga težava

Obstaja pa tudi težava drugačne narave. Recimo, da zdaj želimo uporabiti našo funkcijo dvakrat, nato pa seštejemo rezultate. Kot rezultat bomo dobili takšno kodo:

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

func();

Že spominja na callback hell, kajne? Dodajmo še en klic funkcije - koda bo postala še slabša:

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

func();

Seveda lahko uporabimo Promise.all:

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

func();

Toda, ali smo dobili isto? Ne! V prvem primeru vsaka nova funkcija čaka na zaključek prejšnjega promisa, v drugem primeru pa se vsi promisi izvajajo sočasno. Ta razlika bo pomembna v primeru, ko bomo želeli v naslednjo funkcijo posredovati klic prejšnje:

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

func();