Masalah Promise Hell dalam JavaScript

Anda telah pun tahu bahawa janji (promise) dicipta untuk menyelesaikan masalah callback hell. Walau bagaimanapun, lama-kelamaan ternyata bahawa janji juga mampu menghasilkan kod yang rumit. Masalah ini dengan analogi dipanggil promise hell.

Mari kita lihat masalah ini dengan contoh kod. Katakan kita mempunyai fungsi getSmth, yang menerima parameter dan mengembalikan hasil bergantung pada parameter tersebut:

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

Dalam kes ini, kita mengimitasi beberapa operasi berguna (misalnya, mendapatkan data dari pelayan). Sebagai imitasi, kita hanya menghantar nombor sebagai parameter dan selepas satu saat mengembalikan kuasa dua nombor tersebut.

Sekarang mari kita gunakan fungsi kita getSmth di dalam fungsi lain:

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

func();

Masalah Pertama

Banyak konstruksi then yang mengikut satu sama lain menyukarkan pemahaman kod:

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

func();

Masalah Kedua

Terdapat juga masalah jenis lain. Katakan sekarang kita mahu menggunakan fungsi kita dua kali, kemudian jumlahkan hasilnya. Hasilnya kita akan mendapat kod seperti ini:

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

func();

Sudah menyerupai callback hell, bukan? Mari tambah satu lagi panggilan fungsi - kod akan menjadi lebih teruk:

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

func();

Sudah tentu, kita boleh menggunakan Promise.all:

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

func();

Walau bagaimanapun, adakah kita mendapat perkara yang sama? Tidak! Dalam kes pertama, setiap fungsi baru menunggu janji (promise) sebelumnya selesai, manakala dalam kes kedua - semua janji dilaksanakan serentak. Perbezaan ini akan ketara dalam kes apabila kita mahu menghantar panggilan sebelumnya ke fungsi seterusnya:

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

func();