JavaScriptの醍醐味である非同期処理におけるPromiseの使い方等についてまとめてみました!
「 The Complete JavaScriipt Course 2020:Build Real Project! 」というUdemyのJavaScript動画講座を中心に学習し、不明点を公式リファレンス等で補う形のスタイルで学習を進めて得たものをアウトプットしたいと思います!
Promise
Promiseとは、サーバーとの通信のように失敗する可能性がある処理をする時に、それがうまくいったかどうかを判定して、その結果に応じてその後の処理を変えることが出来るオブジェクト。
Promiseを使用する際は、
- Promiseに関数をひっつける
- new演算子をPromiseの前に記載
- Promiseの下にthenとcatchを記載
new Promise((resolve,reject) => {
// ここにPromiseによって成功or失敗を判定したい処理を記載
resolve(/*処理が成功した時にthenに受け渡したい値を記載*/)
})
.then(result => {
//処理が成功した時に実行する処置(コード)を記載
})
.catch(error => {
//処理が失敗した時に実行する処置(コード)を記載
});
Promiseに関数をひっつける
と書いていますが、MDNではその関数のことをexecutorと呼んでいます。
(https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise)
このexecutorが処理の結果(成功か失敗か)に応じて、その後の処理を決めていると思われます。
new演算子を記載
new演算子を使いインスタンスを作成することでPromiseがPromiseとして機能することになります。
then
then以降にはPromiseで記載した処理が成功した場合の処理を関数の形で書く。
引数を1つ与えることで、その引数に最初のPromise内部で取得したデータを引き渡すことができる。
catch
catch以降にはPromiseで記載した処理が失敗した場合の処理を関数の形で書く。
引数を1つ与えることで、その引数にエラーが返る。
上のコードの空白の部分を書き進めると以下のようになります。
new Promise((resolve,reject) => {
setTimeout(pub => {
const data = [1,2,3]
resolve(data[0])
},1500)
})
.then(result => {
console.log(result); //data配列の1が表示されます
})
.catch(error => {
console.log(error);
});
引数resolveに続く形で、then以降に受け渡したいデータを記載する必要があります。引数の名前は何でもよいですが、処理が成功した場合に取得されるデータは1個目の引数に入れられthenに引き渡されます。
ここでの処理はsetTimeout関数で実施しており処理に失敗しようがないので、失敗時の検証ができません。そのため、次にfetchを使用して実際に外部のサーバーからデータを取得する処理で説明を行います。
サーバーからデータ取得して成功、失敗を判定
webAPIからデータを取得するにはfetchを使用します。
new Promise((resolve,reject) => {
const data = fetch(`https://jsonplaceholder.typicode.com/todos/1`)
resolve(data)
})
.then(result => {
console.log(result); //データ取得に成功するとResponseが表示される
})
.catch(error => {
console.log(error); //データ取得に失敗するとTypeErrorが表示される
});
上記のコードを実行して、コンソールを開くと、Responseと表示され、データが取得されているのが分かると思います。
試しにPCのインターネット接続を切断して、上記コードを実行してみると、TypeErrorが返ってきます。ここまで実行するとPromiseが正常に働いているのを実感できるのではないかと思います。
より進化した書き方
上記の書き方でも実行できるのですが、変数に代入する形でPromiseを使用することもできます。
実際のコードがこちらです。
const getData = new Promise((resolve,reject) => {
const data = fetch(`https://jsonplaceholder.typicode.com/todos/1`)
resolve(data)
})
getData
.then(result => {
console.log(result); //データ取得に成功するとResponseが表示される
})
.catch(error => {
console.log(error); //データ取得に失敗するとTypeErrorが表示される
});
この書き方でも、先ほどと同様の結果になります。
MDNではPromiseのコンストラクタとしての説明に、
コンストラクタは主に、まだ Promise をサポートしていない関数をラップするのに使用されます。(https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise)
と記載されていますが、ここで行ったことがまさにこのことだと解釈しました。
100%正確かどうかは保証できませんが、上記の引用文は「コンストラクタは主に、変数をPromiseとして扱えるようにするために使用されます。」に言い換えられるのでは無いかと考えています。
fetchについて
先ほどfetchを使用しましたが、実はその場合コードをもう少し単純にすることができます。
fetch(`https://jsonplaceholder.typicode.com/todos/1`)
.then(result => {
console.log(result); //データ取得に成功するとResponseが表示される
})
.catch(error => {
console.log(error); //データ取得に失敗するとTypeErrorが表示される
});
これでも同様の結果が得られます。
これがなぜ正常に動作するかについての説明としては、MDNのfecthのページに根拠になりうる記載を見つけました。(https://developer.mozilla.org/ja/docs/Web/API/WindowOrWorkerGlobalScope/fetch)
上記ページの冒頭部分によるとfetchはPromiseを返すとのことです。
うまいこと説明できてないかもしれませんが、fetchそのものにPromiseの機能が備わっていると思っても良いかもしれません。
終わりに
JavaScriptを勉強して日が浅いこともあり、すべてを説明できていませんし、正式な解釈、表現ではない部分もあったかもしれませんが、私と同じ初心者の方にとってはPromiseについて勉強するきっかけにはなろうかと思います。もし、先輩エンジニアの方が記事を読んでいただき、異論、訂正、ダメ出し、お叱り等々ある場合メッセージ頂けると非常にありがたく思います!
最後まで読んでいただきありがとうございました!