async と awaitに関して
どうもフロントエンドエンジニアのoreoです。前回の「Promiseに関して」の続きとして、async
、await
と例外処理に関して記載します!
1 async と awaitとは?
async
、await
を利用すると、Promise
をさらに直感的に記述することができます。
-
async
-
async
を使うと、Promise
オブジェクトを返却する関数を宣言できます。
-
-
await
-
Promise
オブジェクトをreturn
する関数の前にawait
をつけると、Promise
がresolve
またはreject
されるまで待機することができます。待機中は、await
以降の処理は中断され、待機が終わると以降の処理が再開されます。 -
await
は、async
内で使用します。
-
2 基本的な使い方
Promise
構文の復習
2-1 「Promiseに関して」で、記載したPromise
チェーンは以下ex1~ex2のようなものでした。
関数apple
は、Promise
を用いて、非同期処理が実装されています。
【ex1】
function apple(num) {
return new Promise(function (resolve) {
setTimeout(function () {
console.log(`りんごは${num}個`);
num += 1;
resolve(num);
}, 1000);
});
}
Promise
を使った場合には、.then
メソッドで、非同期処理の後に実行したい処理を繋げることができました。
【ex2】
/**
* 以下が1秒毎に出力
* りんごは1個
* りんごは2個
* りんごは3個
* 終了! ※これは「りんごは3個」と同時に出力
*/
apple(1)
.then(function (num) {
return apple(num);
})
.then(function (num) {
return apple(num);
})
.then(function (num) {
apple(num);
console.log("終了!")
})
async
、await
を使う
2-2 このex2の処理をasync
、await
を使って、簡略化するとex3のようになります。
まず、async
を使って関数appleAsync
を定義し、その中でawait
を使って関数apple
に引数1を渡します。await apple(1)
では、関数apple
で、resolve
された値が返されます。その値を変数val
に代入し、続いてawait apple(val)
をval
に再代入していくことで、ex2と同じ挙動をとることができます。
ここで、await
をつけた処理は、resolve
が呼ばれるまで(非同期処理が終わるまで)、待機状態となり、それ以降の処理は中断されます。全ての非同期処理が終了した後に、console.log("終了!")
は実行されます。
【ex3】
/**
* 以下が1秒毎に出力
* りんごは1個
* りんごは2個
* りんごは3個
* 終了! ※これは「りんごは3個」と同時に出力
*/
async function appleAsync(){
let val = await apple(1) //関数appleでresolveされた値(ここでは2)がvalに代入される
val = await apple(val) //3がvalに代入される
val = await apple(val) //4がvalに代入される
console.log("終了!")
}
appleAsync()
ex3での関数appleAsync()
は、Promise
を返すため、関数appleAsync()
を実行した後に.then
メソッドを繋げることができます。
【ex4】
/**
* 以下が出力。
* りんごは1個
* appleAsyncから2が取得できます
*/
async function appleAsync(){
let val = await apple(1) //関数appleでresolveされた値(ここでは2)がvalに代入される
return val
}
appleAsync()
.then(function (val) {
console.log(`appleAsyncから${val}が取得できます`);
})
また、関数appleAsync()
内でthrow new Error()
を呼ぶと、.catch
に繋げることも可能です。
【ex5】
async function appleAsync() {
let val = await apple(1);
throw new Error();
return val;
}
appleAsync()
.then(function (val) {
console.log(`appleAsyncから${val}が取得できます`);
})
.catch(function (e) {
console.error(e); //Error !!!
});
3 使いどころ
fetch
などでのデータ取得やエラーハンドリングでよく使いますね。
fetch
でデータを取得する
3-1 fetch
メソッドを使えば、HTTPリクエストを発行して、サーバーなどからデータを取得できます。fetch
メソッドは、Promise
オブジェクトを返却します。
ここで下記のようなfruits.jsonからfetch
メソッドを用いてデータを取得したいと思います。
【fruits.jsonファイル】
[
{
"name": "Apple",
"price": 150
},
{
"name": "Orange",
"price": 100
}
]
fetch
メソッドはPromise
オブジェクトを返すので、.then
を使ってfetch
メソッドでresolve
された値を取得できます(ex6)。
【ex6】
fetch("fruits.json").then((data) => {
console.log(data)
})
resolve
された値を見てみると、HTTPステータスコードなどが格納されたオブジェクトが確認できます。
プロトタイプを見てみると、さまざまなメソッドが準備されています。
それらの中で、.json
メソッドを使うとJSONデータを取得できます(ex7)。
【ex7】
/**
* 以下が出力
* [{"name": "Apple","price": 150},{"name": "Orange","price": 100}]
*/
fetch("fruits.json").then((data) => {
return data.json() //jsonを取得して、returnする
}).then((json)=>{
console.log(json)
});
これらをasync
、await
を使って書き換えると、【ex8】のようになります。
【ex8】
/**
* 以下が出力
* [{"name": "Apple","price": 150},{"name": "Orange","price": 100}]
*/
async function fetchFruits() {
const data = await fetch("fruits.json");
const fruits = await data.json(); //.jsonは、Promiseをreturnするのでawaitする
console.log(fruits);
}
fetchFruits();
3-2 例外処理(エラーハンドリング)
例外処理とはエラーが発生した場合に行う処理のことで、【ex9】のようにtry
、catch
、finally
を用いて実装します。
try
ブロックの中でエラーが発生した場合に、それ以降の処理は行わずcatch
ブロックに移行して、エラーハンドリングを行ないます。
【ex9】
try {
//tryの処理でエラーを投げるとそれ以降の処理は行わずcatchに移行する
throw new Error();
} catch (e) {
// エラー時の処理(エラーハンドリング)を行う
console.error(e)
} finally {
//try、catchに関わらず行う終了処理を記載
}
3-1で作成したfruits.jsonをfetch
するような処理で例外処理を実装するとex10のように記載できます。ここでは、データを取得する関数としてfetchFruits
を定義し、fetchが失敗した場合は、throw new Error("データ取得失敗!");
、jsonが空だと、throw new Error("データがないよ!");
を投げます。
また、取得したデータを出力する関数として、outputFruits
を定義します。try
ブロックの中でfetchFruits
関数を実行し、throw new Error()
が実行されると、そのエラーをcatch
ブロックのconsole.error(e);
でエラー内容を確認できます。
【ex10】
//fruitsを取得する関数
async function fetchFruits() {
const data = await fetch("fruits.json");
//data.okには、fetchが成功したかどうかのbooleanが格納されている
if (data.ok) {
const fruits = await data.json();
//jsonが空だとエラー投げる
if (!fruits.length) {
throw new Error("データがないよ!");
}
return fruits;
}else{
throw new Error("データ取得失敗!");
}
}
//fruitsを出力する関数
async function outputFruits() {
try {
const fruits = await fetchFruits();
console.log(fruits);
} catch (e) {
console.error(e);
} finally {
console.log("終了です");
}
}
outputFruits();
最後に
前回のPromise
に続いて、async
、await
や例外処理を整理しました。ここら辺は押さえておきたい内容ですね。
Discussion