Inferno de retorno de chamada significa que você está dentro de um retorno de chamada ou dentro de outro retorno de chamada e ele vai para a enésima chamada até que suas necessidades não sejam atendidas.
Vamos entender por meio de um exemplo de chamada ajax falsa usando a API de tempo limite definido, vamos assumir que temos uma API de receita, precisamos baixar todas as receitas.
<body>
<script>
function getRecipe(){
setTimeout(()=>{
const recipeId = [83938, 73838, 7638];
console.log(recipeId);
}, 1500);
}
getRecipe();
</script>
</body>
No exemplo acima, após 1,5 segundo quando o temporizador expira, o código de retorno de chamada será executado, em outras palavras, por meio de nossa chamada ajax falsa, todas as receitas serão baixadas do servidor. Agora precisamos baixar os dados de uma receita específica.
<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>
Para baixar os dados de uma receita específica, escrevemos o código em nosso primeiro retorno de chamada e passamos o Id da receita
Agora, digamos que precisamos baixar todas as receitas do mesmo editor da receita cujo 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>
Para preencher nossas necessidades, que é baixar todas as receitas do nome da editora suru, escrevemos o código dentro de nosso segundo retorno. É claro que escrevemos uma cadeia de retorno de chamada chamada inferno de retorno de chamada.
Se quiser evitar o inferno do retorno de chamada, você pode usar Promise, que é o recurso js es6, cada promessa recebe um retorno de chamada que é chamado quando uma promessa é cumprida. O retorno de chamada de promessa tem duas opções: é resolvido ou rejeitado. Suponha que sua chamada de API seja bem-sucedida, você pode chamar resolve e passar dados por meio do resolve ; você pode obter esses dados usando then () . Mas se sua API falhar, você pode usar rejeitar, usar catch para detectar o erro. Lembre-se de uma promessa, sempre use então para resolver e pegue para rejeitar
Vamos resolver o problema anterior do callback hell usando uma 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>
Agora baixe a receita particular:
<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>
Agora podemos escrever outra chamada de método allRecipeOfAPublisher como getRecipe, que também retornará uma promessa, e podemos escrever outro then () para receber a promessa de resolução de allRecipeOfAPublisher, espero que neste ponto você possa fazer isso sozinho.
Portanto, aprendemos como construir e consumir promessas, agora vamos tornar o consumo de uma promessa mais fácil usando async / await, que é apresentado no 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>
No exemplo acima, usamos uma função assíncrona porque ela será executada em segundo plano, dentro da função assíncrona usamos a palavra-chave await antes de cada método que retorna ou é uma promessa porque esperar nessa posição até que a promessa seja cumprida, em outras palavras no códigos abaixo até getIds concluído resolvido ou rejeitado programa irá parar de executar códigos abaixo daquela linha quando IDs retornados, então chamamos novamente a função getRecipe () com um id e esperamos usando a palavra-chave await até que os dados retornassem. Então foi assim que finalmente nos recuperamos do inferno de callback.
async function getRecipesAw(){
const IDs = await getIds;
console.log(IDs);
const recipe = await getRecipe(IDs[2]);
console.log(recipe);
}
Para usar o await, precisaremos de uma função assíncrona, podemos retornar uma promessa, então use para resolver promessa e cath para rejeitar promessa
do exemplo acima:
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);
});