【JavaScript】promiseオブジェクトとは?メリットや使い方
この記事からわかること
- promiseとは?
- 3つのpromisestatusの違い
- 使い方とメリット
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
JavaScriptを学び出した私ですが「promise」についてなかなかうまく理解できなかったので備忘録も兼ねてまとめていきます。不備や至らぬ点、勘違いなどがありましたら教えていただけると助かります。
promise(プロミス)のメリット
promise(プロミス)とはJavaScriptの中の非同期処理の結果を取得できる仕組みのことです。
非同期処理とは「処理の終了を待たずに次の処理を行うこと」。JavaScriptは基本的に非同期で処理が進んでいくので例えば以下のようなコードの場合希望の順番に出力されません。
console.log("1回目");
setTimeout(() => {
console.log("2回目");
},1000);
console.log("3回目");
// 結果
1回目
3回目
2回目
しかしこのようにJavaScriptが非同期で処理を行ってくれることで時間のかかる処理やタイミングのずれた処理を後続の処理に影響を与えることなくこなすことができているのは大きなメリットでもあります。
非同期処理が終了した後に処理を行うために役に立つのがpromiseです。promiseを使って先程のコードを書くと以下のようになり、希望の順番通りに出力されるようになります。
console.log("1回目");
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("2回目");
// これは成功させた時の処理なので resolve関数を呼び出す
resolve();
},1000);
})
promise.then((value) => {
// 2回目の出力が成功したら3回目を表示
console.log("3回目");
});
// 結果
1回目
2回目
3回目
promiseの最大のメリットは非同期処理終了後の結果に応じて処理を分岐できることです。これによりプログラムの中で行いたい処理の順番を明確に指定することができます。promise(約束)の意味通り、意図した処理順番を約束してくれるのがpromiseのメリットだと思います。
インスタンス化したpromiseの中では、非同期処理が成功なら「resolve(日本語で解決の意)」、失敗なら「reject(日本語で拒絶の意)」という関数を呼び出します。プロミスを使うことで非同期処理通信の成否によって処理を分岐させることが可能になります。
まとめ
- JavaScriptは基本的に非同期で処理する
- 非同期処理とは処理の結果を待たずに後続の処理を行う仕組み
- 処理の順番を約束してくれるのがpromise
- promiseを使えば非同期処理の結果で後続の処理を分岐させられる
promiseの正体と3つのステータス
promiseの正体はオブジェクトです。使用するにはnew演算子
を使ってインスタンス化します。インスタンス化したpromiseオブジェクトを表示させると以下のように表示されます。
const promise = new Promise((resolve, reject) => {
});
console.log(promise);
// Promise {} ~~ Object[[PromiseState]]: "pending"[[PromiseResult]]: undefined
promiseオブジェクトはpromiseStatus
というプロパティを保持していて3つの状態に変化しながら管理されています。
- pending:初期状態
- fulfilled:成功
- rejected:失敗
console
でオブジェクトを出力すれば現在のステータスを確認できます。ステータスが成功であればthenメソッドで、失敗であればcatchメソッドで後続の処理を記述することができます。
ステータスの値を切り替える方法は引数に渡されているresolve
とreject
という2つのコールバック関数(コールバック関数とは?)です。promiseの中でどちらかのコールバック関数を実行することでステータスの値が切り替わります。
例えばステータスを成功に変えたい場合は、resolve関数
を実行します。 resolve関数の前に任意の処理を記述すれば通常のコードのように上から順番に処理されていくので、「その処理が終わればステータスが切り替わる」ような仕組みを作ることができます。
const promise = new Promise((resolve, reject) => {
// ここに結果を取得したい処理を記述
resolve('成功!');
});
promise.then((value) => {
console.log(value);
// 成功!
});
promiseは自動で中に記述した処理結果を取得するわけでなく、自分でこの処理が終わったら成功(resolve関数を呼び出す)、この処理なら失敗(reject関数を呼び出す)といったようにルートを作っていきながら使います。
コールバック関数(resolveとreject)を使ってステータスを変更した後はthenメソッド
とcatchメソッド
を使って後続の処理を記述していきます。
まとめ
- promiseの正体はオブジェクト
- promiseは3つのステータスで管理されている
- 引数のコールバック関数を呼び出すことでステータスの値を切り替えることができる
- 成功ならthenメソッドで後続の処理を記述
- 失敗ならcatchメソッド後続の処理を記述
コールバック関数とthenメソッド
ここでは先程出てきた2つのポイントをもう少し深掘りしたいと思います。興味がなければ飛ばしてください。
promiseを扱う上で重要になってくるのは先ほど登場した3つ。
- コールバック関数
- thenメソッド
- catchメソッド
コールバック関数とは?
コールバック関数とは関数の中で実行される関数のことを指します。通常関数を定義したら以下のように実行します。
function hello() {
return 'hello";
}
hello(); // 結果:hello
JavaScriptでは関数も変数の中に格納して扱うことができます。なのでこの関数を例えば変数func
に格納して呼び出しの際に引数として渡すこともできるのです。
funcHello = function hello() {
return 'hello";
}
function callMethod(func) {
func();
}
callMethod(funcHello);; // 結果:hello
ここでいうcallMethod
の中で呼び出している関数(ここでいうfuncHello
)をコールバック関数と呼びます。自分で実行するのではなく、他の関数から呼び出されることを前提として定義実行されます。
thenメソッドとは
thenメソッドはpromise status
がresolved
の時に後続に処理させたいコードを記述できるメソッドです。promiseオブジェクトに対してthenメソッドを呼び出す形で使用します。thenメソッドの引数にはresolve関数の引数に指定した値を受け取ることもできます。
promise.then(onFulfilled[, onRejected]);
promise.then(value => {
// resolve(成功)の時に実行させたい処理
}, reason => {
// reject(失敗)の時に実行させたい処理
});
thenメソッドは戻り値としてpromiseオブジェクトを返すのでさらにここからメソッドチェーンで繋げることができます。メソッドチェーンでの直列処理については後述します。
catchメソッドとは
rejectedの時
に後続の処理を記述する場合はcatchメソッド
を使います。使い方はthenメソッドと変わりません。こちらも同様にプロミスオブジェクトを返すのでメソッドチェーンが使用できます。
promise.catch(() => {
console.log("rejectしたよ");
});
メソッドチェーンを使った直列処理
promiseを使うことで非同期処理が絡んでも処理の順番を約束してくれることがわかりました。では実際に希望の順番に処理させる実際の方法を見ていきます。
ここで実現したいことは3つの処理を順番通りに行うことです。非同期の処理が絡むことによって順番がややこしくなりがちなコードをpromiseを使って記述していきます。
const promise = new Promise((resolve, reject) => {
console.log("即座に表示");
setTimeout(() => {
console.log("1秒後に表示");
resolve('1秒後が成功したお');
}, 1000);
})
.then((val) => {
console.log(`then1: ${val}`);
return val;
})
.catch((val) => {
console.log(`catch: ${val}`);
return val;
})
.then((val) => {
console.log(`then2: ${val}`);
});
// 結果:
即座に表示
1秒後に表示
1秒後が成功したお
then1:1秒後が成功したお
then2:1秒後が成功したお
このようにpromiseを使うことで非同期の処理が絡んだ(1秒後に処理するなど)場合でも意図した通りの順番で処理を行わせることができます。またresolveの引数にデータを与えることもできます。メソッドチェーンで受け取るにはthenメソッドの引数に適当な変数を用意して受け取ってください。
ついでにアロー関数の記述方法MEMO
アロー関数を使うことで関数が簡単に書けるようになります。
●通常
function (a){
return a + 100;
}
●アロー関数
(a) => {
return a + 100;
}
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。