非同期処理を実行する際に利用する Promiseオブジェクト.
何となく分かるが、実際にコードを書いてみようとすると困ってしまう。という状況有りませんでしょうか。
何かが分かっていないが、何が分かっていないのか….という状況でした。
疑問として湧いてきたことをベースに、Promiseオブジェクトについてまとめていきたいと思います。
Q1:Promiseオブジェクトとは?
Promiseオブジェクトを単純に表現すると、状態を持つオブジェクトです。
3つの状態があります。
・保留中(pending)
・成功(fulfilled)
・失敗(reject)
Promiseオブジェクトは常に3つのどれかの状態を持ちます。
これらの状態を持つという特徴があるからこそ、非同期処理を作ることが出来ます。
Q2:Promiseの状態はいつ変わる?
成功するか、失敗するかで、状態が変わります。
そのまんま過ぎますかね。では、次へ。
Q3:Promiseの成功 / 失敗はどう決まる?
非常に単純化すると、resolveが実行されたら成功・rejectが実行されたら失敗です。
Promiseオブジェクトの中身をconsoleで確認していきます。
conosole 結果 / 保留中(pending)
const promise = new Promise( (resolve, reject ) => { }) console.log(promise);
Promise {<pending>} [[Prototype]]: Promise [[PromiseState]]: "pending" [[PromiseResult]]: undefined
Promiseオブジェクトは、[PromiseState] , [PromiseResult] の2つを持ちます。
上記では、PromiseStateはpendingとなっています。状態が何も変わっていない初期状態です。
conosole 結果 / 成功(fulfilled)
次に、Promiseの中でresolveを実行してみます。
const promise = new Promise( (resolve, reject ) => { resolve(); }) console.log(promise);
Promise {<fulfilled>: undefined} [[Prototype]]: Promise [[PromiseState]]: "fulfilled" [[PromiseResult]]: undefined
resolve()が実行されたPromiseは成功(fulfilled)の状態に変化しています。
conosole 結果 / ・失敗(reject)
次は予想がつくかと思いますが、
Promiseの中でrejectを実行してみます。
const promise = new Promise( (resolve, reject ) => { reject(); }) console.log(promise);
Promise {<rejected>: undefined} [[Prototype]]: Promise [[PromiseState]]: "rejected" [[PromiseResult]]: undefined
成功のときと同様に
reject()が実行されたPromiseは失敗(reject)の状態に変化しています。
Q4:あれ? resolve, reject って、何?
ここで、ふと思ったのはresolve, reject って何だろうということでした….
結論から言うと、Promiseオブジェクトの
・第一引数:resolve
・第二引数:reject
※両方とも関数です。
名称は何でもOKで、第一引数に指定した関数が実行されれば成功、第二引数に指定した関数が実行されれば失敗 ※reject(第二引数)は省略が可
consoleで確認します。
const promise = new Promise( (daiichiHikisu, reject ) => { daiichiHikisu(); }) console.log(promise);
Promise {<fulfilled>: undefined} [[Prototype]]: Promise [[PromiseState]]: "fulfilled" [[PromiseResult]]: undefined
resolve()を実行したときと同じく、成功(fulfilled)となっています。
つまり、名称は何でもOKで、第一引数に指定した関数が実行されれば成功となるのです。
Q5:PromiseResultは何?
Q4まで、PromiseオブジェクトのPromiseStateについて調べてきました。その間、PromiseResultは全てundefinedでした。
PromiseResultは、resolve OR rejectで返す値です。
const promise = new Promise( (resolve, reject ) => { resolve("success"); }) console.log(promise);
Promise {<fulfilled>: 'success'} [[Prototype]]: Promise [[PromiseState]]: "fulfilled" [[PromiseResult]]: "success"
resolve()で返した値が、PromiseResultに含まれます。
Q6:で、非同期処理とPromiseオブジェクトの関係とは?
Promiseオブジェクトは、PromiseStateが変わることで状態が変化することはよく分かりました。結局、Promiseオブジェクトが非同期処理をどの様に実現するのでしょうか。
非同期処理を実現するために、Promiseオブジェクトの処理に大事なメソッドがあります。それは、then()と catch()です。
then(): Promiseの結果、fulfilledの場合に実行
catch(): Promiseの結果、rejectの場合に実行
実際に、consoleで確認します。
const promise = new Promise( (resolve, reject ) => { resolve(); }) .then(() => { console.log("resolveしたよ"); }) .catch(() => { console.log("rejectしたよ"); });
conosole 結果 / 成功(fulfilled)
resolveしたよ
逆に、rejectの場合
const promise = new Promise( (resolve, reject ) => { reject(); }) .then(() => { console.log("resolveしたよ"); }) .catch(() => { console.log("rejectしたよ"); });
conosole 結果 / ・失敗(reject)
rejectしたよ
となります。
下記の通りにthen, catchがそれぞれ実行されます。
then(): Promiseの結果、fulfilledの場合に実行 catch(): Promiseの結果、rejectの場合に実行
Q7:ででで、結局、非同期処理とPromiseオブジェクトの関係とは?
結局のところ、これで非同期処理をどうやって実現するのでしょうか。
・Promiseオブジェクトは状態を持つ
・状態に合わせて処理を変更できる
この2つの特性を利用して、非同期処理を実現することが出来ます。
setTimeout関数を利用して、1000ms後にresolve(“success”)を実行する関数を作ります。returnでPromiseオブジェクトを返します。
promiseAfter1000ms() { return new Promise((resolve, reject) => { setTimeout(() => { resolve("success") }, 1000) }) }
そして、この関数の実行に対してthen(), catch()で状態に合わせて処理を実行します。
this.getValueAfter1000ms() .then(() => { console.log("good") }) .catch(() => { console.log("error") })
conosole 結果 / 成功(fulfilled)
Promiseオブジェクトが成功(fulfilled)の際に実行されるthen()内のconsoleが、1000ms後に処理されます。
good
conosole 結果 / ・失敗(reject)
次に、reject処理が実行されるPromiseへ変更すると
promiseAfter1000ms() { return new Promise((resolve, reject) => { setTimeout(() => { reject("misstake") }, 1000) }) }
catch()内のconsoleが、1000ms後に処理されます。
error
Q8:より実践的に、Promiseオブジェクトで非同期処理を実行するには?
Q7にて、1000ms後に、Promiseの状態に応じて実行する非同期処理を記述しました。しかし、分かったような分からないような、使いみちがイメージしづらいかもしれません。
より実践的な処理にてイメージを掴みましょう。
サーバーにPostリクエストした後に、そのレスポンスデータが返ってきた後に実行する非同期処理を考えてみます。
サーバーにPostする処理をaxiosを使って書いていきます。
axiosとは、axiosの設定については触れません。
既知ではない方は、サーバーにリクエストしている。くらいに思っておいて下さい。
Promiseオブジェクトの中に axios処理を記述しています。
getServerData() { return new Promise( (resolve, reject) => { this.$axios.$post('/api/ques', { name: "test",}) // axios処理 .then(res => resolve( res )) .catch(res => reject( res )) }) },
補足
※Postリクエストにて、nameプロパティに文字列testを送信 ※axios処理自体も非同期処理になっている ※axios処理が成功した場合(fulfilled)、レスポンスでresが返ってくる
上記のaxiosによりPostする処理の結果を受けて、非同期処理を実行します。
axiosによるPostリクエストが成功した場合、thenが実行されます。失敗した場合にはcatchが実行されます。
this.getServerData() .then((res) => { console.log(res) }) .catch((res) => { console.log(res) })
■参考にさせて頂いた情報