JavaScript
 Computer >> コンピューター >  >> プログラミング >> JavaScript

JavaScriptのPromise(プロミス)とは?使い方を初心者向けにわかりやすく解説

JavaScriptで非同期処理を書くのは、かつて非常に手間のかかる作業でした。非同期操作を実装するには、何層にも重なったコールバック関数を扱う必要があり、関数が増えるほどコードは読みにくくなっていきました。

そんな悩みを解決するためにES6で登場したのが「Promise(プロミス)」です。Promiseを使えば、JavaScriptで効率的に非同期コードを書くことができます。

この記事では、Promiseとは何か、どのように動作するのかを解説し、実際のコード例を通して使い方を学んでいきます。それでは始めましょう!

Promise(プロミス)とは?

Promiseとは、将来受け取りたい結果を返すためのオブジェクトです。

JavaScriptのPromiseは、現実世界での「約束」にたとえると理解しやすくなります。人が約束をするとき、それは将来のある時点で何かを行うことを保証するものです。今すぐ実行するのではなく、後で実行するということですね。

Promiseには次の3つの状態が存在します。

  • Pending(保留中):Promiseがまだ完了していない状態
  • Rejected(拒否):Promiseが値を返すことに失敗した状態
  • Fulfilled(履行済み):Promiseが正常に完了した状態

これは現実の約束とよく似ています。将来実行すると約束すれば、その約束は保留中(Pending)になります。約束を果たせばFulfilledとなり、約束を破ればRejectedとなるのです。

Promiseを作成した直後はPending状態になり、結果を受け取ってFulfilledまたはRejectedに確定するまで、この状態が続きます。

JavaScriptでPromiseを作成する方法

まずは、ユーザーの名前を返すPromiseを作成してみましょう。この関数は3秒後にユーザー名をプログラムへ返します。Promiseを使った非同期コードの書き方がイメージできるはずです。

Promiseを作成するには、Promiseオブジェクトを生成します。

new Promise((resolve, reject) => { 
	// ここにコードを書く
});

Promiseは2つの引数を受け取ります。1つは成功時を処理する関数、もう1つは失敗時を処理する関数です。つまり、Promiseはその結果によって異なる値を返すことになります。

Promiseには、処理が成功したかどうかを判定するif文を含めるのが一般的です。処理が成功しなかった場合は、Rejected状態のPromiseを返すようにします。

new Promise((resolve, reject) => { 
	if (条件がtrueの場合) {
		resolve();
	} else {
		reject();
	}
});

新しいJavaScriptファイルを開いて、以下のコードをコピーしてください。

let returnName = new Promise((resolve, reject) => {
	let name;
	setTimeout(() => {
		name = "Cinnamon";

		if (name === "Cinnamon") {
			resolve(name);
		} else {
			reject("This promise has failed.");
		}
	}, 3000);
});

このコードは、Promiseを呼び出すとメインプログラムに名前「Cinnamon」を返します。実行には3秒(3,000ミリ秒)かかるため、Promiseを呼び出してから3秒間はPending状態になります。Promiseが確定(settle)すると、解決されたか拒否されたかの状態でメインプログラムに返されます。

変数nameが「Cinnamon」と等しければPromiseは正常に解決され、そうでなければ拒否されます。この例ではnameに「Cinnamon」が設定されているため、Promiseは自動的に解決されます。

then()とcatch()を使ったPromiseの処理

まだコードは実行されていません。作成したPromiseオブジェクトを呼び出す必要があります。

returnName.then(data => {
	console.log(data);
});

then()メソッドを使うと、Promiseから応答を受け取ることができます。then()はPromiseが解決された後に呼び出され、この例ではPromiseから返された応答であるdataの中身をコンソールに出力しています。

このコードを実行すると、「Cinnamon」が出力されます。

ただし、then()は成功したPromiseしか処理できません。Promiseが拒否された場合はどうなるのでしょうか?そこで登場するのがcatch()メソッドです。

また、Promise内には複数のthen()文を連ねることもできます。これを「Promiseチェーン」と呼びます。チェーンの仕組みを例で見てみましょう。

returnName.then(data => {
	console.log(data);
}).then(() => {
	console.log("This function is over!");
});

このコードは以下を出力します。

Cinnamon
This function is over!

then()文は、Promiseコンストラクタ内で指定された順序どおりに実行されます。

catch()メソッドもthen()メソッドと同じようにPromiseに連結できます。先ほどの名前の例に、拒否されたPromiseを処理するハンドラーを追加してみましょう。

returnName.then(data => {
	console.log(data);
}).catch(error => {
	console.log(error);
});

then()文の後にcatch()文を連結しました。ここで注意したいのは、Promiseコードの最後にセミコロン(;)を付けることです。catch()を使う場合、then()メソッドの後にセミコロンを付けないでください。セミコロンを付けると、then()とcatch()が別々の文として認識され、エラーが発生してしまいます。

Promiseが拒否された場合、catch()文の中身が実行されます。

実際にコードを実行するとどうなるか見てみましょう。

Cinnamon

「Cinnamon」が返されるのは、Promiseが正常に解決されるからです。もしPromise内のnameの値が「Cinnamon」でなければ、次のようなエラーが返されます。

Uncaught (in promise) This promise has failed.

このエラーメッセージ「This promise has failed.」は、Promise内のreject()関数で指定したものです。

finally()を使ったPromiseの処理

Promiseの成功・失敗に関わらず、処理の完了後に必ず特定のコードブロックを実行したい場合はどうすればよいのでしょうか?

そんなときに便利なのがfinally()文です。finally()文は、PromiseがFulfilledでもRejectedでも、必ず実行されます。Promiseの呼び出しにfinally文を追加してみましょう。

returnName.then(data => {
	console.log(data);
}).catch(error => {
	console.log(error);
}).finally(() => {
	console.log("The returnName promise has been executed.");
});

このコードの出力は以下のとおりです。

Cinnamon
The returnName promise has been executed.

Promiseが成功したため「Cinnamon」が返され、続いてfinally()文の中身が実行され、別のメッセージがコンソールに出力されます。

まとめ

JavaScriptのPromiseを使えば、きれいで読みやすい非同期コードを書くことができます。

この記事では、Promiseの基礎について解説しました。Promiseにはまだまだ奥深い機能があります。学習の次のステップとしては、自分のコードでいくつかPromiseを書いてみることをおすすめします。

ここで一つ課題を出しましょう。Webリクエストを実行してそのレスポンスを返すPromiseを書いてみてください。リクエストにはfetch() APIを使用し、そのリクエストをPromiseで囲みます。Promiseが成功した場合と失敗した場合の両方を処理するコードを書いてみましょう。

さらに学びたい方は、JavaScriptのasync関数について調べてみてください。async関数も非同期コードを書くために使われ、Promiseと組み合わせてよく利用されます。

これであなたも、プロのようにJavaScriptのPromiseを書く準備が整いました!

  1. JavaScriptのPromise(プロミス)とは?非同期処理の基本と使い方を解説

    JavaScriptのPromise(プロミス)は、作成された時点ではまだ値が確定していない非同期処理を扱うためのオブジェクトです。APIリクエストやファイルの読み込みなど、完了まで時間がかかる処理について、「いずれ結果を受け取る」という約束を表現します。Promiseは、以下の3つの状態を持ちます。pending(保留中):処理がまだ完了しておらず、成功も失敗も確定していない初期状態fulfilled(履行済み):処理が正常に完了し、結果の値が利用できる状態rejected(拒否済み):処理が失敗し、エラーの理由が利用できる状態一度fulfilledまたはrejectedに遷移したPromi

  2. JavaScript関数で名前付き引数を使う方法|分割代入で簡単に実現するテクニック

    JavaScriptにおける名前付き引数とは? Pythonなどの言語には「名前付き引数(キーワード引数)」という機能が標準で備わっていますが、JavaScriptにはこの機能が組み込まれていません。しかし、オブジェクトの分割代入(Destructuring)を活用することで、名前付き引数と同じ挙動を簡単に実現できます。 基本的な仕組み 関数の引数としてオブジェクトを1つ受け取り、その中から必要なプロパティを分割代入で取り出します。各プロパティにはデフォルト値も同時に指定できるため、引数が省略された場合でもエラーにならず安全に処理できます。 サンプルコード 以下は、オブジェクトを引数として渡し