Promiseオブジェクトとは何か. ~QAで深堀る~
非同期処理を実行する際に利用する Promiseオブジェクト.
何となく分かるが、実際にコードを書いてみようとすると困ってしまう。という状況有りませんでしょうか。
何かが分かっていないが、何が分かっていないのか....という状況でした。
疑問として湧いてきたことをベースに、Promiseオブジェクトについてまとめていきたいと思います。
Q1:Promiseオブジェクトとは?
Promiseオブジェクトを単純に表現すると、状態を持つオブジェクトです。
3つの状態があります。
- 保留中(pending)
- 成功(fulfilled)
- 失敗(reject)
Promiseオブジェクトは常に3つのどれかの状態を持ちます。これらの状態を持つという特徴があるからこそ、非同期処理を作ることが出来ます。
Q2:Promiseの状態はいつ変わる?
成功するか、失敗するかで、状態が変わります。
そのまんま過ぎますかね。では、次へ。
Q3:Promiseの成功 / 失敗はどう決まる?
非常に単純化すると、resolveが実行されたら成功・rejectが実行されたら失敗です。
Promiseオブジェクトの中身をconsoleで確認していきます。
保留中(pending)
const promise = new Promise( (resolve, reject ) => {
})
console.log(promise);
promise返却
Promise {<pending>}
[[Prototype]]: Promise
[[PromiseState]]: "pending"
[[PromiseResult]]: undefined
上記では、PromiseStateはpendingとなっています。状態が何も変わっていない初期状態です。
成功(fulfilled)
次に、Promiseの中でresolveを実行してみます。
const promise = new Promise( (resolve, reject ) => {
resolve();
})
console.log(promise);
promise返却
Promise {<fulfilled>: undefined}
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: undefined
resolve()が実行されたPromiseは 成功(fulfilled) の状態に変化しています。
失敗(reject)
次は、Promiseの中でrejectを実行してみます。
const promise = new Promise( (resolve, reject ) => {
reject();
})
console.log(promise);
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で確認します。
resolveの場合
const promise = new Promise( (resolve, reject ) => {
resolve();
})
.then(() => {
console.log("resolveしたよ");
})
.catch(() => {
console.log("rejectしたよ");
});
resolveしたよ
rejectの場合
const promise = new Promise( (resolve, reject ) => {
reject();
})
.then(() => {
console.log("resolveしたよ");
})
.catch(() => {
console.log("rejectしたよ");
});
rejectしたよ
下記の通りにthen, catchがそれぞれ実行されます。
- then(): Promiseの結果、fulfilledの場合に実行
- catch(): Promiseの結果、rejectの場合に実行
Q7:結局、非同期処理とPromiseオブジェクトの関係とは?
結局のところ、これで非同期処理をどうやって実現するのでしょうか。
- Promiseオブジェクトは状態を持つ
- 状態に合わせて処理を変更できる
この2つの特性を利用して、非同期処理を実現することが出来ます。
setTimeout関数を利用して、1000ms後にPromiseオブジェクトを返却する関数を作ります。
resolveを返す
getValueAfter1000ms() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("success")
}, 1000)
})
}
そして、この関数の実行に対してthen(), catch()で状態に合わせて処理を実行します。
this.promiseAfter1000ms()
.then(() => { console.log("good") })
.catch(() => { console.log("error") })
Promiseオブジェクトが成功(fulfilled)の際に実行されるthen()内のconsoleが、1000ms後に処理されます。
good
rejectを返す
promiseAfter1000ms() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject("misstake")
}, 1000)
})
}
そして、この関数の実行に対してthen(), catch()で状態に合わせて処理を実行します。
this.promiseAfter1000ms()
.then(() => { console.log("good") })
.catch(() => { console.log("error") })
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が実行されます。
参考
Discussion