よくわからないまま放置していたPromiseがとても便利でした。基本的なことですが、備忘録。
関数の処理が終わったら何かしたい
昔ながらのコールバック関数をずっと使い続けていました。例えば500ms経過したら成功か失敗を返すhoge関数があるとします。
コールバック関数
function hoge(cb = null) {
setTimeout(() => {
if (Math.random() < 0.5) {
cb('成功');
} else {
cb('失敗');
}
cb(true);
}, 500);
}
hoge((result) => console.log(result));
引数にcallback関数を渡す場合はこのようになると思います。一応これでも動きますが、どうも泥臭い感じになってしまいます。
Promise
function hoge() {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() < 0.5) {
resolve('成功');
} else {
reject('失敗');
}
}, 500);
});
}
hoge()
.then((result) => console.log(result))
.catch((error) => console.error(error));
同じ処理をPromiseに置き換えたものがこちら。
new Promiseを返すことで、コール側が非同期処理を制御できます。resolveは成功、rejectは失敗のコールバックと同じです。resolve は then で受け、reject は catch で受けます。
thenで成功、catchで失敗の処理を明示できているのもわかりやすくて良いです。
Promise.allでPromiseをまとめて処理する
Promiseはオブジェクトなので、まとめて扱うこともできます。
Promise.allでの実行
const promises = [];
for (let i=0; i<2; i++) {
promises.push(new Promise((resolve, reject) => {
setTimeout(() => {
Math.random() < 0.5 ? resolve(`成功:${i}`) : reject(`失敗:${i}`);
}, 500 * Math.random());
}));
}
Promise.all(promises)
.then((result) => console.log(result))
.catch((error) => console.error(error));
Promise.allの場合、どれか1つでも reject すると catch() しか呼ばれません。すべて resolve の場合のみ then() が呼ばれます。
上の例の場合、2つのPromiseをまとめて実行し、結果は以下の3パターンどれかになります。
"失敗:0"
"失敗:1"
["成功:0", "成功:1"]
Promise.allでrejectがあった場合の実行結果
reject の場合、最初に reject になった結果のみが返されます。
1つ目が失敗なら”失敗:0″、2つ目が失敗なら”失敗:1″だけが返り、他の結果はわかりません。
Promise.allでrejectがない場合の実行結果
reject がなく、すべて resolve の場合は配列で結果が返ります。配列内の順序は resolve を呼び出した順番ではなく、Promise.all()の引数の順番です。
setTimeout(() => {
}, 500 * Math.random());
上の例ではこのように完了タイミングをランダムにしていますが、成功の場合は常に [“成功:0”, “成功:1”] です。
[“成功:1”, “成功:0”] という順序で返ることはありません。
まとめ
とりあえず使ってみることが大事。
スッキリすると保守性も上がって気分も良いです。