非同期処理を実行する際に利用する 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) })
■参考にさせて頂いた情報
- https://www.tohoho-web.com/ex/promise.html
- https://qiita.com/cheez921/items/41b744e4e002b966391a
- https://hidekazu-blog.com/javascript-promise