Vấn đề promise hell trong JavaScript
Bạn đã biết rằng Promise được tạo ra để giải quyết vấn đề callback hell. Tuy nhiên, theo thời gian, người ta nhận thấy rằng Promise cũng có thể tạo ra code phức tạp. Vấn đề này theo phép loại suy được gọi là promise hell.
Hãy cùng xem xét vấn đề này qua các ví dụ
code. Giả sử chúng ta có hàm getSmth,
nhận một tham số và trả về kết quả
tùy thuộc vào tham số đó:
function getSmth(num) {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(num * num), 1000)
});
}
Trong trường hợp này, chúng ta đang mô phỏng một thao tác hữu ích (ví dụ: lấy dữ liệu từ máy chủ). Để mô phỏng, chúng ta chỉ cần truyền một số làm tham số và sau một giây trả về bình phương của số đó.
Bây giờ hãy sử dụng hàm của chúng ta
getSmth bên trong một hàm khác:
function func() {
getSmth(2).then(res => {
console.log(res); // sẽ hiển thị 4
});
}
func();
Vấn đề thứ nhất
Nhiều cấu trúc then nối tiếp nhau
làm khó hiểu code:
function func(){
getSmth(2).then(res1 => {
// làm gì đó
}).then(res2 => {
// làm gì đó
}).then(res3 => {
// làm gì đó
}).then(res4 => {
// làm gì đó
}).then(res5 => {
// làm gì đó
}).then(res6 => {
// làm gì đó
});
}
func();
Vấn đề thứ hai
Cũng có một vấn đề theo hướng khác. Giả sử bây giờ chúng ta muốn sử dụng hàm của mình hai lần, sau đó tính tổng các kết quả. Kết quả là chúng ta sẽ có code như thế này:
function func() {
getSmth(2).then(res1 => {
getSmth(3).then(res2 => {
console.log(res1 + res2); // sẽ hiển thị 13
});
});
}
func();
Đã bắt đầu giống callback hell rồi, phải không? Thêm một lần gọi hàm nữa - code sẽ còn tệ hơn:
function func() {
getSmth(2).then(res1 => {
getSmth(3).then(res2 => {
getSmth(4).then(res3 => {
console.log(res1 + res2 + res3);
});
});
});
}
func();
Tất nhiên, có thể sử dụng Promise.all:
function func() {
Promise.all([getSmth(2), getSmth(3), getSmth(4)]).then(res => {
console.log(res[0] + res[1] + res[2]);
});
}
func();
Tuy nhiên, chúng ta có nhận được kết quả giống nhau không? Không! Trong trường hợp đầu tiên, mỗi hàm mới đều chờ promise trước đó hoàn thành, còn trong trường hợp thứ hai - tất cả các promise được thực hiện đồng thời. Sự khác biệt này sẽ rất quan trọng trong trường hợp khi chúng ta muốn truyền kết quả của hàm trước vào hàm tiếp theo:
function func() {
getSmth(2).then(res1 => {
getSmth(res1).then(res2 => {
getSmth(res2).then(res3 => {
console.log(res3);
});
});
});
}
func();