Праblema promise hell у JavaScript

Вы ўжо ведаеце, што промісы былі створаны для таго, каб вырашыць праблему callback hell. Аднак, з часам апынулася, што промісы таксама здольныя параждаць складаны код. Гэтая праblema па аналогіі была названа promise hell.

Давайце расгледзім гэтую праблему на прыкладах кода. Хай у нас ёсць функцыя getSmth, якая атрымлівае параметр і вяртае вынік у залежнасці ад гэтага параметра:

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

У гэтым выпадку мы імітуем некаторую карысную аперацыю (напрыклад, атрыманне дадзеных з сервера). У якасці імітацыі мы проста параметрам перадаем лік і праз секунду вяртаем квадрат гэтага ліку.

Давайце цяпер скарыстаемся нашай функцыяй getSmth унутры іншай функцыі:

javascriptfunction func() {
  getSmth(2).then(res => {
    console.log(res); // выведзе 4
  });
}

func();

Першая праблема

Мноства наступных адзін за адным канструкцый then ускладняюць разуменне кода:

javascriptfunction func(){
  getSmth(2).then(res1 => {
    // робім што-небудзь
  }).then(res2 => {
    // робім што-небудзь
  }).then(res3 => {
    // робім што-небудзь
  }).then(res4 => {
    // робім што-небудзь
  }).then(res5 => {
    // робім што-небудзь
  }).then(res6 => {
    // робім што-небудзь
  });
}

func();

Другая праблема

Ёсць праблема і іншага плана. Хай цяпер мы хочам скарыстацца нашай функцыяй два разы, затым прасумаваць вынікі. У выніку ў нас атрымаецца вось такі код:

javascriptfunction func() {
  getSmth(2).then(res1 => {
    getSmth(3).then(res2 => {
      console.log(res1 + res2); // выведзе 13
    });
  });
}

func();

Ужо нагадвае callback hell, ці не так? Дадамо яшчэ адзін вызаў функцыі - код стане яшчэ горшым:

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

func();

Можна, вядома ж, скарыстацца Promise.all:

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

func();

Аднак, ці атрымалі мы тое ж самае? Не! У першым выпадку кожная новая функцыя чакае завяршэння папярэдняга проміса, а ў другім выпадку - усе промісы выконваюцца адначасова. Гэтая розніца будзе істотная ў тым выпадку, калі мы ў наступную функцыю захочам перадаць вызаў папярэдняй:

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

func();