Promiseについて
Promiseなしで同期処理
setTimeout(() => console.log(1), 1000); setTimeout(() => console.log(2), 2000); setTimeout(() => console.log(3), 0);
上記の処理結果は下記のようになる。
3 1 2
これはJavaScriptが一つ前の実行に時間が掛かった場合、実行結果を待たずに次の処理が行われる為である。 このような処理を「非同期処理」という。
それではこれを順番に「1 2 3」と表示されるにはどうすればよいか?(関数の順番を並び替えるは無し) 下記のようにコールバックを用いることで実現できる。
setTimeout(() => { console.log(1); setTimeout(() => { console.log(2); setTimeout(() => { console.log(3); }, 0); }, 2000); }, 1000);
しかし、見て分かる通り上記のような単純な処理を実現しようと思ってもコールバックを多用するとコードの見通しが悪くなってしまう。 これがより複雑な処理を実現しようとするとバグの温床になりかねない。
このようなコールバック地獄を解決し、直感的にJavaScriptで同期処理を実現するために使用するのがPromise
である!!
Promise
Promiseは直訳すると「約束」という意味なので、要するに処理の実行順を約束してくれるものというイメージでOK。
Promiseには以下の3つ状態がある。
- 待機 (pending): 初期状態。成功も失敗もしていないことを意味する
- 解決済み (resolved): 処理が成功して完了したことを意味する
- 拒否 (rejected): 処理が失敗したことを意味する
resolvedしたPromiseはthen()
で定義された関数, rejectedしたPromiseはcatch()
定義された関数が実行される。
前述したコールバック地獄をPromiseを使用すると下記のような感じになる。
const promise1 = new Promise((resolve, reject) => { setTimeout(() => resolve(console.log(1), 1000)); }); const promise2 = new Promise((resolve, reject) => { setTimeout(() => resolve(console.log(2), 2000)); }); const promise3 = new Promise((resolve, reject) => { setTimeout(() => resolve(console.log(3), 0)); }); promise1.then(() => promise2).then(() => promise3) // 結果 // 1 // 2 // 3
resolve, rejectのパラメーターで定義したものはそれぞれthen(), catch()の第一引数に渡される。
const cookRice = new Promise((resolve, reject) => { console.log('ご飯を炊き始めました'); const duration = 6 * 1000; setTimeout(() => { resolve('ご飯が炊けました'); }, duration); }); cookRice.then((message) => { console.log(message); // 'ご飯が炊けました' }); const cookRice = new Promise((resolve, reject) => { console.log('ご飯を炊き始めました'); const duration = 6 * 1000; setTimeout(() => { reject('炊飯器が壊れたので炊けませんでした'); }, duration); }); cookRice.catch((message) => { console.log(message); });
所感
promiseを何となく使用していましたが、今回調べてみたことで基本的な概念を学ぶことができました。 また、以前はコールバックを多用して書かないといけない時代があることを知り、改めてpromiseのありがたさが分かりましたw