🌟

Promiseオブジェクトとは何か. ~QAで深堀る~

2024/11/21に公開

非同期処理を実行する際に利用する 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オブジェクトの関係とは?

結局のところ、これで非同期処理をどうやって実現するのでしょうか。

  1. Promiseオブジェクトは状態を持つ
  2. 状態に合わせて処理を変更できる
    この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が実行されます。

参考

https://www.tohoho-web.com/ex/promise.html
https://qiita.com/cheez921/items/41b744e4e002b966391a
https://hidekazu-blog.com/javascript-promise

Discussion