Promiseを少しでも理解できるようになるために
JavaScriptで非同期処理を実行する時に必ず通らないといけない道...それはpromise
です。
昨今のフロントエンド開発では非同期処理とはうまく付き合っていかなければならないのですが、
「Promise...とは...?」となっている人にとってpromise
を理解するのは難しいです。
かくいう私もだいぶ苦戦してやっと使えるようになった側なので、理解するのは難しいと思っています。
この記事が少しでも役に立てれば幸いです。
Promiseとは
プロミス (Promise) は、作成された時点では分からなくてもよい値へのプロキシーです。非同期のアクションの成功値または失敗理由にハンドラーを結びつけることができます。これにより、非同期メソッドは結果の値を返す代わりに、未来のある時点で値を提供するプロミスを返すことで、同期メソッドと同じように値を返すことができるようになります。
MDNより抜粋:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise
Promiseで大事なこと
- Promiseには状態があります。以下の3パターンです。
1.pending
- 初期状態で待機しています。成功も失敗もしていません。
2.fulfilled
- 処理が成功していて、かつ完了したことを意味します。
3.reject
- 処理が失敗したことを意味します。
Promiseの基本構文
new Promise((resolve, reject) => {
// resolve() ...処理が成功した場合
// reject() ...処理が失敗した場合
});
Promiseで遊んでみる
早速、Promise
で非同期関数を作って遊んでみましょう。
asyncFunction
という関数で、状態がresolve
した時に文字列を返す関数を作って見ました。
const asyncFunction = () => {
return new Promise((resolve) => {
resolve("async Hello");
});
};
さて、この関数をこのまま実行したらどうなるでしょうか。
成功も失敗もしていません。Promiseオブジェクト
が返されました。
Promise { 'async Hello' }
ここからが大事なのですが、Promise
の結果を得るには、ハンドラを使って値を返す必要があります。
結果を得たいのはresolve
なのでthen()
を使って値を返します。
asyncFunction().then((value) => console.log(value));
// 実行結果: async Hello
今度はreject
を返すバージョンを作ってみます。
reject
の結果を値として返す場合はcatch()
を使って値を返します。
const asyncFunction = () => {
return new Promise((resolve, reject) => {
reject("...reject");
});
};
asyncFunction().catch((value) => console.log(value));
// 実行結果: ...reject
rejectの結果をエラーハンドリングをする
関数の引数に、配列と特定の値を入れて、配列内に特定の値が含まれているかどうかを判定する非同期関数を作って見ます。reject
が返ってくる時はエラーハンドリングを加えます。
const existValue = (array, value) => {
return new Promise((resolve) => {
if (array.includes(value)) return resolve(`${value}は配列に含まれています`);
throw new Error(`${value}は配列に含まれていません`);
});
};
existValue([1, 2, 3], 4)
.then((value) => {
console.log(value);
})
.catch((error) => {
if (error instanceof Error) {
console.log(error.message);
}
});
// 実行結果: 4は配列に含まれていません
ところでなぜ、reject
を書いていないのに、エラーハンドリングされたのでしょうか?
.then()
ハンドラの中でthrow
したため、自動的にreject
と判断されたのです。
なので、reject
を明記した場合は以下のように書けて、同様の意味になります。
return reject(new Error(`${value}は配列に含まれていません`));
どうですか、Promise
面白いですよね?
aysnc / await
Promise
が理解できたら次はasync / await
について簡単に触れたいと思います。
async / await
とpromise
を併用して、
先ほど、「rejectの結果をエラーハンドリングをする」で書いた関数を書き換えて見ましょう。
メソッドチェーンで制御していた部分はtry ~ catch
を使って制御します。
イメージとしてメソッドチェーンの.then()
で処理を待っていた部分にawait
を使って、非同期処理の実行を待ちます。
const existValue = async (array, value) => {
return await new Promise((resolve) => {
if (array.includes(value)) return resolve(`${value}は配列に含まれています`);
throw new Error(`${value}は配列に含まれていません`);
});
};
(async () => {
try {
const result = await existValue([1, 2, 3], 4);
console.log(result);
} catch (error) {
if (error instanceof Error) {
console.log(error.message);
}
}
})();
// 実行結果: 4は配列に含まれていません
ということでPromise
についての説明でした。
Promise
は奥深いのですが、理解できないと悩んでいる方のお力になれたら幸いです。
Discussion