Call back hell significa che sei all'interno di un callback o di un altro callback e va all'ennesima chiamata finché le tue esigenze non vengono soddisfatte.
Comprendiamo attraverso un esempio di falsa chiamata ajax utilizzando l'API set timeout, supponiamo di avere un'API di ricetta, dobbiamo scaricare tutta la ricetta.
<body>
<script>
function getRecipe(){
setTimeout(()=>{
const recipeId = [83938, 73838, 7638];
console.log(recipeId);
}, 1500);
}
getRecipe();
</script>
</body>
Nell'esempio sopra, dopo 1,5 sec quando il timer scade all'interno del codice di richiamata verrà eseguito, in altre parole, tramite la nostra falsa chiamata ajax tutte le ricette verranno scaricate dal server. Ora dobbiamo scaricare i dati di una ricetta particolare.
<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>
Per scaricare i dati di una ricetta particolare, abbiamo scritto il codice all'interno della nostra prima richiamata e abbiamo passato l'ID della ricetta.
Supponiamo ora di dover scaricare tutte le ricette dello stesso editore della ricetta il cui 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>
Per soddisfare le nostre esigenze, ovvero scaricare tutte le ricette del nome dell'editore suru, abbiamo scritto il codice all'interno della nostra seconda call back. È chiaro che abbiamo scritto una catena di callback che si chiama callback hell.
Se vuoi evitare l'inferno di richiamata, puoi usare Promise, che è la funzione js es6, ogni promessa riceve una richiamata che viene chiamata quando una promessa è piena. promise callback ha due opzioni o è risolto o rifiuta. Supponiamo che la tua chiamata API abbia esito positivo, puoi chiamare la risoluzione e passare i dati attraverso la risoluzione , puoi ottenere questi dati usando then () . Ma se la tua API non è riuscita, puoi usare rifiuta, usa catch per catturare l'errore. Ricordate che una promessa utilizzare sempre poi per determinazione e cattura per respingere
Risolviamo il precedente problema dell'inferno di richiamata usando una promessa.
<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>
Ora scarica la ricetta particolare:
<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>
Ora possiamo scrivere un altro metodo chiamato allRecipeOfAPublisher come getRecipe che restituirà anche una promessa, e possiamo scrivere un altro then () per ricevere la promessa di risoluzione per allRecipeOfAPublisher, spero che a questo punto tu possa farlo da solo.
Quindi abbiamo imparato come costruire e consumare promesse, ora rendiamo più facile consumare una promessa usando async / await che è introdotto in 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>
Nell'esempio sopra, abbiamo usato una funzione asincrona perché verrà eseguita in background, all'interno della funzione asincrona abbiamo usato la parola chiave await prima di ogni metodo che ritorna o è una promessa perché aspettare in quella posizione fino a quando quella promessa non viene soddisfatta, in altre parole nel i codici seguenti fino a quando getIds non saranno stati risolti o il programma di rifiuto interromperà l'esecuzione dei codici sotto quella riga quando gli ID sono stati restituiti, quindi abbiamo chiamato di nuovo la funzione getRecipe () con un ID e abbiamo aspettato utilizzando la parola chiave await finché i dati non sono stati restituiti. Quindi è così che finalmente ci siamo ripresi dall'inferno del callback.
async function getRecipesAw(){
const IDs = await getIds;
console.log(IDs);
const recipe = await getRecipe(IDs[2]);
console.log(recipe);
}
Per usare await avremo bisogno di una funzione asincrona, possiamo restituire una promessa quindi usa then per risolvere promessa e cath per rifiutare promessa
dall'esempio sopra:
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);
});