Promise hell -ongelman JavaScriptissä
Tiedät jo, että promiset luotiin ratkaisemaan callback hell -ongelma. Kuitenkin ajan myötä kävi ilmi, että promiset voivat myös synnyttää monimutkaista koodia. Tätä ongelmaa kutsutaan analogisesti nimellä promise hell.
Tarkastellaan tätä ongelmaa koodiesimerkkien
avulla. Oletetaan, että meillä on funktio getSmth,
joka saa parametrin ja palauttaa tuloksen
riippuen tästä parametristä:
function getSmth(num) {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(num * num), 1000)
});
}
Tässä tapauksessa imitoimme jotain hyödyllistä toimintoa (esimerkiksi tietojen hakemista palvelimelta). Imitaationa välitämme parametrina yksinkertaisesti luvun ja palautamme sekunnin kuluttua sen neliön.
Hyödynnetään nyt funktiotamme
getSmth toisen funktion sisällä:
function func() {
getSmth(2).then(res => {
console.log(res); // tulostaa 4
});
}
func();
Ensimmäinen ongelma
Useat peräkkäiset then
-rakenteet vaikeuttavat koodin ymmärtämistä:
function func(){
getSmth(2).then(res1 => {
// teemme jotain
}).then(res2 => {
// teemme jotain
}).then(res3 => {
// teemme jotain
}).then(res4 => {
// teemme jotain
}).then(res5 => {
// teemme jotain
}).then(res6 => {
// teemme jotain
});
}
func();
Toinen ongelma
On olemassa toisenlainen ongelma. Oletetaan nyt, että haluamme hyödyntää funktiotamme kaksi kertaa ja laskea tulokset yhteen. Tuloksena saamme tällaisen koodin:
function func() {
getSmth(2).then(res1 => {
getSmth(3).then(res2 => {
console.log(res1 + res2); // tulostaa 13
});
});
}
func();
Muistuttaa jo callback helliä, eikö vain? Lisätään vielä yksi funktiokutsu - koodista tulee vielä huonompi:
function func() {
getSmth(2).then(res1 => {
getSmth(3).then(res2 => {
getSmth(4).then(res3 => {
console.log(res1 + res2 + res3);
});
});
});
}
func();
Voisimme tietysti hyödyntää Promise.all:
function func() {
Promise.all([getSmth(2), getSmth(3), getSmth(4)]).then(res => {
console.log(res[0] + res[1] + res[2]);
});
}
func();
Mutta saimmeko saman tuloksen? Ei! Ensimmäisessä tapauksessa jokainen uusi funktio odottaa edellisen promisen valmistumista, kun taas toisessa tapauksessa - kaikki promiset suoritetaan samanaikaisesti. Tämä ero on merkittävä silloin, kun haluamme välittää seuraavaan funktioon edellisen funktion tuloksen:
function func() {
getSmth(2).then(res1 => {
getSmth(res1).then(res2 => {
getSmth(res2).then(res3 => {
console.log(res3);
});
});
});
}
func();