JavaScriptのPromise・async・awaitを使ってみる

IEのサポートが終了になったので、JavaScriptのPromise・async・awaitの使い方を改めて試してみます。

Promise

Promiseオブジェクトは、非同期処理の完了や失敗などの状態を表します。
Promiseには以下の3つの状態があります。

  • pending(待機): 処理前または処理中で、成功も失敗もしていない状態。
  • fulfilled(履行): 処理が完了して成功した状態。
  • rejected(拒否): 処理が完了して失敗した状態。

new Promise()で実際にPromiseオブジェクトを作成して、各状態を確認してみます。

const promise = new Promise((resolve, reject) => {});
console.log(promise); // 処理完了前なのでpendingの状態

const promise2 = new Promise((resolve, reject) => {
	// 何らかの処理
	resolve(); // 処理成功時
});
console.log(promise2); // 処理が成功しているのでfulfilledの状態

const promise3 = new Promise((resolve, reject) => {
	// 何らかの処理
	reject(); // 処理失敗時
});
console.log(promise3); // 処理が失敗しているのでrejectedの状態

1~2行目はPromiseオブジェクトを作成したのみで処理を完了していないのでpendingの状態です。
new Promise()の関数内で、処理成功時には第一引数に設定しているresolve()、処理失敗時には第二引数に設定しているreject()を実行することで、Promiseオブジェクトの状態をfulfilledやrejectedに変更できます。
Promiseのデモページ

次に処理が終わった後にthen()とcatch()につなぐ流れを試してみます。
処理成功の状態(fulfilled)になった後はthen()、処理失敗の状態(rejected)になった後はcatch()のコールバックが実行されます。
その際に、resolve()やreject()の引数に与えた値をコールバックで使用できます。

const promise = new Promise((resolve, reject) => {
	setTimeout(() => {
		resolve('A'); // 処理成功時
	}, 1000);
});
promise.then((data) => {
	console.log('resolveのテスト 処理成功', data); // こちらが実行される
}).catch((error) => {
	console.log('resolveのテスト 処理失敗', error);
});

const promise2 = new Promise((resolve, reject) => {
	setTimeout(() => {
		reject('B'); // 処理失敗時
	}, 1000);
});
promise2.then((data) => {
	console.log('rejectのテスト 処理成功', data);
}).catch((error) => {
	console.log('rejectのテスト 処理失敗', error); // こちらが実行される
});

1つ目の例では成功時のresolve()を実行しているのでthen()のコールバック、2つ目の例では失敗時のreject()を実行しているのでcatch()のコールバックが実行されています。
Promiseのデモページ2

Promiseオブジェクトを返す別の例として、fetchを試してみます。

const url1 = './data.json';
const test1 = fetch(url1);
console.log(test1); // 処理完了前なのでpendingの状態

test1.then((response) => {
	console.log('fetchのテスト 処理成功'); // こちらが実行される
	console.log(test1); // 処理が成功しているのでfulfilledの状態
	console.log(response);
	return response.json(); // jsonの中身を取得
}).then((data) => {
	console.log(data);
}).catch((error) => {
	console.log('fetchのテスト 処理失敗');
	console.log(test1);
	console.log(error);
});

const url2 = './nothing.json'; // 存在しないファイル取得の場合
const test2 = fetch(url2);
console.log(test2); // 処理完了前なのでpendingの状態

test2.then((response) => {
	console.log('fetchのテスト 処理成功'); // 存在しないファイル(404)だけどthenの方に入る
	console.log(test2); // fulfilledの状態
	console.log(response);
	return response.json(); // jsonを取得していないのでエラーになり、catch()に入る (Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0)
}).then((data) => {
	console.log(data);
}).catch((error) => {
	console.log('fetchのテスト 処理失敗'); // fetchのエラーではなく、json()のエラーでここに入る
	console.log(test2);
	console.log(error);
});

fetch()の時点ではHTTPレスポンス全体の取得になるので、jsonの中身を取得するためさらにjson()を使っています。
json()もPromiseオブジェクトを返すので、then()でさらに繋いでいます。
fetchのデモページ

fetchの注意点として、fetchのレスポンスが404の場合でもfulfilled(履行)の状態になるため、then()の処理に入ります。
上記2つ目の例でもjson()でのエラーで最終的にはcatch()に入っていますが、fetch()で取得した時点ではcatch()ではなくthen()の方に入っています。
これは仕様的にこのような挙動になっているようで、ネットワーク障害があった場合などにrejected(拒否)の状態になります。

async/await

asyncは非同期関数の宣言で使用され、その中でawaitを使用することができます。
awaitはPromiseから状態が返されるのを待つ際に使われます。

実際にasyncとawaitを使ってみます。

// Promiseを返す関数
const promiseFunc = () => {
	return new Promise((resolve, reject) => {
		setTimeout(() => {
			resolve('A');
		}, 1000);
	});
}

const asyncFunc = async () => {
	const result = await promiseFunc(); // promiseFunc() から値が返ってくるまで待つ
	console.log(result); // A
}

asyncFunc();

10行目でasyncを使って非同期関数の宣言を行い、関数内の11行目のpromiseFunc()がPromiseを返す関数なので、awaitで値が返ってくるまで待つようにしています。
asyncとawaitのデモページ

Promiseの時と同じように、fetchを使った例で試してみます。

const asyncFunc = async () => {
	const url = './data.json';
	const result = await fetch(url); // fetch() から値が返ってくるまで待つ
	console.log(result);
	const json = await result.json(); // jsonの中身を取得
	console.log(json);
}

asyncFunc();

意図したとおりの動作を確認できました。
asyncとawaitのデモページ2

参考サイト

このエントリーをはてなブックマークに追加

関連記事

コメントを残す

メールアドレスが公開されることはありません。
* が付いている欄は必須項目です

CAPTCHA


コメントが承認されるまで時間がかかります。

2024年4月
 123456
78910111213
14151617181920
21222324252627
282930