Пекло зворотного дзвінка означає, що ви знаходитесь всередині зворотного дзвінка всередині іншого зворотного дзвінка, і він переходить до n-го виклику, поки ваші потреби не будуть повноцінними.
Давайте розберемося на прикладі фальшивого виклику ajax, використовуючи встановлений API очікування, припустимо, у нас є API рецепту, нам потрібно завантажити весь рецепт.
<body>
<script>
function getRecipe(){
setTimeout(()=>{
const recipeId = [83938, 73838, 7638];
console.log(recipeId);
}, 1500);
}
getRecipe();
</script>
</body>
У наведеному вище прикладі через 1,5 секунди, коли закінчиться таймер, всередині коду виклику буде виконуватися, іншими словами, через наш підроблений виклик ajax, весь рецепт буде завантажений з сервера. Тепер нам потрібно завантажити конкретні дані рецепту.
<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>
Щоб завантажити конкретні дані рецепту, ми написали код всередині нашого першого зворотного виклику та передали ідентифікатор рецепта.
Тепер скажімо, що нам потрібно завантажити всі рецепти того самого видавця рецепту, id якого - 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>
Щоб повністю заповнити наші потреби, а саме - завантажити всі рецепти назви видавця suru, ми написали код всередині нашого другого дзвінка. Зрозуміло, що ми написали зворотний дзвінок, який називається пеклом зворотного дзвінка.
Якщо ви хочете уникнути пекло зворотного дзвінка, ви можете використовувати Promise, який є функцією js es6, кожна обіцянка приймає зворотний виклик, який викликається, коли обіцянка заповнена повністю. Обіцяння зворотного виклику має два варіанти: він вирішений, або відхилений. Припустимо, ваш виклик API вдалий, ви можете викликати дозвіл на виклик та передавати дані через дозвіл. Ви можете отримати ці дані, використовуючи тоді () . Але якщо ваш API не вдався, ви можете скористатися відхиленням, використовуйте catch, щоб знайти помилку. Пам'ятайте обіцянку завжди використовувати потім для рішучості і улову для відхиляти
Давайте вирішимо попередню пекельну проблему зворотного дзвінка за допомогою обіцянки.
<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>
Тепер скачайте конкретний рецепт:
<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>
Тепер ми можемо написати інший метод виклику allRecipeOfAPublisher, як getRecipe, який також поверне обіцянку, і ми можемо написати інший тоді (), щоб отримати обіцянку вирішення для allRecipeOfAPublisher, я сподіваюся, що в цей момент ви можете зробити це самостійно.
Таким чином ми дізналися, як будувати обіцянки та споживати, тепер давайте полегшити використання обіцянки за допомогою функції async / await, яка введена в 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>
У наведеному вище прикладі ми використовували функцію async, оскільки вона буде працювати у фоновому режимі, всередині функції async ми використовували ключове слово очікування перед кожним методом, який повертається або є обіцянкою, тому що чекати на цій позиції, поки ця обіцянка не буде виконана, іншими словами в внизу коди, поки програма getIds не буде завершена або відхилена, програма перестане виконувати коди нижче цього рядка, коли ідентифікатори повернулися, тоді ми знову викликали функцію getRecipe () з ідентифікатором і чекали, використовуючи ключове слово очікування, поки дані не повернуться. Так ось, нарешті, ми оговталися від пекла зворотного дзвінка.
async function getRecipesAw(){
const IDs = await getIds;
console.log(IDs);
const recipe = await getRecipe(IDs[2]);
console.log(recipe);
}
Для використання в режимі очікування нам знадобиться функція асинхронізації, ми можемо повернути обіцянку, тож використовуйте тоді для вирішення обіцянки та поступка для відхилення обіцянки
з наведеного вище прикладу:
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);
});