ปัญหาของ promise hell ใน JavaScript

คุณทราบอยู่แล้วว่าพรอมิสถูกสร้างขึ้นเพื่อ แก้ไขปัญหาของ callback hell อย่างไรก็ตาม ภายหลังปรากฏว่าพรอมิส ก็สามารถสร้างโค้ดที่ซับซ้อนได้เช่นกัน ปัญหานี้ ถูกเรียกโดยเปรียบเทียบว่า 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();