Gọi lại địa ngục có nghĩa là bạn đang ở trong một cuộc gọi lại bên trong một cuộc gọi lại khác và nó sẽ chuyển sang cuộc gọi thứ n cho đến khi nhu cầu của bạn không được đáp ứng đầy đủ.
Chúng ta hãy hiểu một ví dụ về lệnh gọi ajax giả bằng cách sử dụng API thời gian chờ đã đặt, giả sử chúng ta có API công thức, chúng tôi cần tải xuống tất cả công thức.
<body>
<script>
function getRecipe(){
setTimeout(()=>{
const recipeId = [83938, 73838, 7638];
console.log(recipeId);
}, 1500);
}
getRecipe();
</script>
</body>
Trong ví dụ trên, sau 1,5 giây khi bộ đếm thời gian hết hạn, mã lệnh gọi lại sẽ thực thi, nói cách khác, thông qua lệnh gọi ajax giả của chúng tôi, tất cả công thức sẽ được tải xuống từ máy chủ. Bây giờ chúng ta cần tải xuống một dữ liệu công thức cụ thể.
<body>
<script>
function getRecipe(){
setTimeout(()=>{
const recipeId = [83938, 73838, 7638];
console.log(recipeId);
setTimeout(id=>{
const recipe = {title:'Fresh Apple Juice', publisher:'Suru'};
console.log(`${id}: ${recipe.title}`);
}, 1500, recipeId[2])
}, 1500);
}
getRecipe();
</script>
</body>
Để tải xuống một dữ liệu công thức cụ thể, chúng tôi đã viết mã bên trong lệnh gọi lại đầu tiên và chuyển Id công thức.
Bây giờ, giả sử chúng ta cần tải xuống tất cả các công thức nấu ăn của cùng một nhà xuất bản công thức có id là 7638.
<body>
<script>
function getRecipe(){
setTimeout(()=>{
const recipeId = [83938, 73838, 7638];
console.log(recipeId);
setTimeout(id=>{
const recipe = {title:'Fresh Apple Juice', publisher:'Suru'};
console.log(`${id}: ${recipe.title}`);
setTimeout(publisher=>{
const recipe2 = {title:'Fresh Apple Pie', publisher:'Suru'};
console.log(recipe2);
}, 1500, recipe.publisher);
}, 1500, recipeId[2])
}, 1500);
}
getRecipe();
</script>
</body>
Để đáp ứng đầy đủ nhu cầu của chúng tôi, đó là tải xuống tất cả các công thức nấu ăn của tên nhà xuất bản suru, chúng tôi đã viết mã bên trong cuộc gọi lại thứ hai của chúng tôi. Rõ ràng là chúng tôi đã viết một chuỗi gọi lại được gọi là địa ngục gọi lại.
Nếu bạn muốn tránh gọi lại địa ngục, bạn có thể sử dụng Promise, đây là tính năng js es6, mỗi lời hứa nhận một lệnh gọi lại được gọi khi một lời hứa được điền đầy đủ. Gọi lại lời hứa có hai tùy chọn hoặc nó được giải quyết hoặc từ chối. Giả sử lệnh gọi API của bạn thành công, bạn có thể gọi giải quyết và chuyển dữ liệu qua giải quyết , bạn có thể lấy dữ liệu này bằng cách sử dụng then () . Nhưng nếu API của bạn không thành công, bạn có thể sử dụng từ chối, sử dụng bắt để bắt lỗi. Hãy nhớ rằng một lời hứa luôn sử dụng sau đó để giải quyết và bắt để từ chối
Hãy giải quyết vấn đề địa ngục gọi lại trước đó bằng cách sử dụng một lời hứa.
<body>
<script>
const getIds = new Promise((resolve, reject)=>{
setTimeout(()=>{
const downloadSuccessfull = true;
const recipeId = [83938, 73838, 7638];
if(downloadSuccessfull){
resolve(recipeId);
}else{
reject('download failed 404');
}
}, 1500);
});
getIds.then(IDs=>{
console.log(IDs);
}).catch(error=>{
console.log(error);
});
</script>
</body>
Bây giờ tải xuống công thức cụ thể:
<body>
<script>
const getIds = new Promise((resolve, reject)=>{
setTimeout(()=>{
const downloadSuccessfull = true;
const recipeId = [83938, 73838, 7638];
if(downloadSuccessfull){
resolve(recipeId);
}else{
reject('download failed 404');
}
}, 1500);
});
const getRecipe = recID => {
return new Promise((resolve, reject)=>{
setTimeout(id => {
const downloadSuccessfull = true;
if (downloadSuccessfull){
const recipe = {title:'Fresh Apple Juice', publisher:'Suru'};
resolve(`${id}: ${recipe.title}`);
}else{
reject(`${id}: recipe download failed 404`);
}
}, 1500, recID)
})
}
getIds.then(IDs=>{
console.log(IDs);
return getRecipe(IDs[2]);
}).
then(recipe =>{
console.log(recipe);
})
.catch(error=>{
console.log(error);
});
</script>
</body>
Bây giờ chúng ta có thể viết một phương thức khác gọi allRecipeOfAPublisher như getRecipe cũng sẽ trả về một lời hứa và chúng ta có thể viết một then () khác để nhận lời hứa quyết định cho allRecipeOfAPublisher, tôi hy vọng tại thời điểm này, bạn có thể tự làm điều đó.
Vì vậy, chúng ta đã học cách xây dựng và sử dụng các lời hứa, bây giờ hãy làm cho việc sử dụng một lời hứa dễ dàng hơn bằng cách sử dụng async / await được giới thiệu trong es8.
<body>
<script>
const getIds = new Promise((resolve, reject)=>{
setTimeout(()=>{
const downloadSuccessfull = true;
const recipeId = [83938, 73838, 7638];
if(downloadSuccessfull){
resolve(recipeId);
}else{
reject('download failed 404');
}
}, 1500);
});
const getRecipe = recID => {
return new Promise((resolve, reject)=>{
setTimeout(id => {
const downloadSuccessfull = true;
if (downloadSuccessfull){
const recipe = {title:'Fresh Apple Juice', publisher:'Suru'};
resolve(`${id}: ${recipe.title}`);
}else{
reject(`${id}: recipe download failed 404`);
}
}, 1500, recID)
})
}
async function getRecipesAw(){
const IDs = await getIds;
console.log(IDs);
const recipe = await getRecipe(IDs[2]);
console.log(recipe);
}
getRecipesAw();
</script>
</body>
Trong ví dụ trên, chúng tôi đã sử dụng một hàm không đồng bộ vì nó sẽ chạy ở chế độ nền, bên trong hàm không đồng bộ, chúng tôi đã sử dụng từ khóa await trước mỗi phương thức trả về hoặc là một lời hứa vì phải đợi ở vị trí đó cho đến khi lời hứa đó được thực hiện, nói cách khác trong mã dưới đây cho đến khi hoàn tất getIds được giải quyết hoặc chương trình từ chối sẽ ngừng thực thi các mã dưới dòng đó khi các ID được trả về sau đó chúng ta lại gọi hàm getRecipe () với một id và đợi bằng cách sử dụng từ khóa await cho đến khi dữ liệu được trả về. Vì vậy, đây là cách cuối cùng chúng tôi đã phục hồi từ địa ngục gọi lại.
async function getRecipesAw(){
const IDs = await getIds;
console.log(IDs);
const recipe = await getRecipe(IDs[2]);
console.log(recipe);
}
Để sử dụng await, chúng ta sẽ cần một hàm async, chúng ta có thể trả về một lời hứa, vì vậy hãy sử dụng then chốt để giải quyết lời hứa và cath để từ chối lời hứa
từ ví dụ trên:
async function getRecipesAw(){
const IDs = await getIds;
const recipe = await getRecipe(IDs[2]);
return recipe;
}
getRecipesAw().then(result=>{
console.log(result);
}).catch(error=>{
console.log(error);
});