コールバック地獄とは、別のコールバック内のコールバック内にいることを意味し、フルフィールドが必要なくなるまでn番目のコールに進みます。
set timeout APIを使用して偽のajax呼び出しの例を理解してみましょう。レシピ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を渡しました。
ここで、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のすべてのレシピをダウンロードするという私たちのニーズを完全に満たすために、2番目のコールバック内にコードを記述しました。コールバック地獄と呼ばれるコールバックチェーンを作成したことは明らかです。
コールバックの地獄を避けたい場合は、js es6機能であるPromiseを使用できます。各Promiseは、Promiseがいっぱいになったときに呼び出されるコールバックを受け取ります。promiseコールバックには、解決するか拒否するかの2つのオプションがあります。あなたの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>
これで、getRecipeなどの別のメソッド呼び出しallRecipeOfAPublisherを記述して、promiseを返すことができます。また、別のthen()を記述して、allRecipeOfAPublisherの解決プロミスを受け取ることができます。この時点で、自分で実行できることを願っています。
そこで、プロミスを作成して使用する方法を学びました。次に、es8で導入されたasync / awaitを使用して、プロミスを簡単に使用できるようにします。
<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>
上記の例では、バックグラウンドで実行されるため、非同期関数を使用しました。非同期関数内では、約束が返されるか、または約束である各メソッドの前にawaitキーワードを使用して、約束が満たされるまでその位置で待機するため、つまりgetIdsが解決されるまでコードを拒否するか、プログラムが拒否されると、IDが返されたときにその行の下のコードの実行が停止し、IDを指定してgetRecipe()関数を再度呼び出し、データが返されるまでawaitキーワードを使用して待機しました。これが最終的にコールバック地獄から回復した方法です。
async function getRecipesAw(){
const IDs = await getIds;
console.log(IDs);
const recipe = await getRecipe(IDs[2]);
console.log(recipe);
}
awaitを使用するには、非同期関数が必要です。promiseを返すことができるため、resolve promiseに使用し、cathをreject promiseに使用します。
上記の例から:
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);
});