はじめに
JavaScript(ES6)で非同期処理を順番に実行するのに便利なPromiseの基本についてまとめました。
1. Promiseオブジェクトの挙動
2. 通常のコールバック関数
3. 上記コールバック関数をPromiseオブジェクトで書き換え
4. Promiseチェーンで非同期処理の順番を指定
の4つに分けて記載してあります。
環境
OS: macOS Catalina 10.15.1
Promiseのメリット
公式ドキュメントより
現在の JavaScript イベントループの実行完了より前には、コールバックが決して呼び出されない。
非同期処理が完了もしくは失敗した後に then() により登録されたコールバックでも、上記のように呼び出される。
then() を何回も呼び出して複数のコールバックを追加してもよく、それぞれのコールバックは追加順に独立して実行される。
つまり、非同期処理の順番がコントロール出来るというのが最大のメリットですね。
本記事では、そんなPromiseの
- 基本的な挙動、
- 従来のコールバック関数との違い
- Promiseチェーン
を確認していきます。
1. Promiseオブジェクトの挙動
まずは、Promiseオブジェクトとはどのようなものか?
シンプルな例で確認してみます。
const samplePromise = new Promise((resolve, reject) => { //Promiseはresolve, rejectの2つの引数を持つ
let a = true //ここをtrue/falseで変更して挙動を確認(後述)
if (a === true) {
resolve('Success') //trueならresolveの()内が返される
} else {
reject('Failed') //falseならrejectの()内が返される
}
})
//出力部
samplePromise.then((message) => { //thenの引数messageはresolveの()内に記述した内容
console.log(`This is in the then ${message}`)
}).catch((message) => { //catchの引数messageはrejectの()内に記述した内容
console.log(`This is in the catch ${message}`)
})
↓
This is in the then Success
This is in the catch Failed
This is in the catch ReferenceError: tru is not defined
出力例3のように、エラーが発生したら、それが引数となるのにも注目です。
では、次にPromiseで置き換える前のコールバック関数をご確認下さい。
2. 通常のコールバック関数
const cat = false //猫が好きならtrueにして下さい
const dog = false //犬が好きならtrueにして下さい
//コールバックで書いた場合
function callbackSample(callback, errorCallback) { //callback関数, errorCallback関数を引数に持つ
if (cat && dog) { //犬猫両方好きな場合
callback('Both dogs and cats are cute :)') //文字列を持つcallbackを返す
} else if (dog) { //犬だけ好きな場合
errorCallback({
name: 'Dog',
message: 'Wan!!'
})
} else if (cat) { //猫だけ好きな場合
errorCallback({
name: 'Cat',
message: 'nyaaaaa~'
})
} else { //...
errorCallback({
name: 'Oh...',
message: 'You may not be friend. :('
})
}
}
//出力部
callbackSample((message) => { //第一引数はcallback関数の()内に渡した文字列
console.log(`Success: ${message}`)
}, (error) => { //第二引数はerrorCallback関数の()内に渡した文字列
console.log(`${error.name} ${error.message}`)
})
↓
Success: Both dogs and cats are cute :)
Dog Wan!!
Cat nyaaaaa~
Oh... You may not be friend. :(
これをPromiseオブジェクトを使って書き換えます。
3. Promiseオブジェクトを使って置き換えた場合
const cat = false //猫が好きならtrueにして下さい
const dog = false //犬が好きならtrueにして下さい
// Promiseで変更後
function promiseSample() { //引数に渡していたcallback, errorCallback関数が不要になる
return new Promise((resolve, reject) => { //Promiseオブジェクトを定義し、その中に全ての処理を書く
if (cat && dog) {
resolve('Both dogs and cats are cute :)') //callback => resolveに置き換える
} else if (dog) {
reject({ //errorCallback => rejectに置き換える
name: 'Dog',
message: 'Wan!!'
})
} else if (cat) {
reject({ //errorCallback => rejectに置き換える
name: 'Cat',
message: 'nyaaaaa~'
})
} else {
reject({ //errorCallback => rejectに置き換える
name: 'Oh...',
message: 'You may not be friend. :('
})
}
})
}
//出力部
promiseSample() //then, catchをメソッドチェーンで繋げる
.then((message) => { //thenでresolveの()内を引数messageで受け取る
console.log(`Success: ${message}`)
})
.catch((error) => { //catchでrejectの()内を引数errorを受け取る
console.log(`${error.name} ${error.message}`)
})
↓
Success: Both dogs and cats are cute :)
Dog Wan!!
Cat nyaaaaa~
Oh... You may not be friend. :(
同様の結果が得られました。
では、次が最後です。非同期処理の順番を指定してみましょう!
4. Promiseチェーンで非同期処理の順番を指定する
以下コードを読む前に、子供が目を閉じて数を数えているシーンを思い浮かべて下さい...きっと理解が進みます。笑
※順番の指定に対して理解しやすくするため、先程までとは違いreject
は使っていません。
function promiseOne() {
return new Promise(resolve => {
setTimeout(() => {
resolve('いーち')
}, 1000) //1秒後に'いーち'という文字列を返す
})
}
function promiseTwo() {
return new Promise(resolve => {
setTimeout(() => {
resolve('にーい')
}, 1000) //1秒後に'にーい'という文字列を返す
})
}
function promiseThree() {
return new Promise(resolve => {
setTimeout(() => {
resolve('さーん')
}, 1000) //1秒後に'さーん'という文字列を返す
})
}
//出力例
promiseOne()
.then(one => { //ここのoneにはpromiseOneのresolveの()内にある文字列が入る
console.log(one)
return promiseTwo() //ここでreturnした結果が次の引数twoに入る
})
.then(two => { //ここのtwoにはpromiseTwoのresolveの()内にある文字列が入る
console.log(two)
return promiseThree() //ここでreturnした結果が次の引数threeに入る
})
.then(three => { //ここのthreeにはpromiseThreeのresolveの()内にある文字列が入る
console.log(three)
})
↓
いーち
いーち
にーい
いーち
にーい
さーん
全て1秒後に文字列を返す関数でしたが、キレイに3秒かけて「いーち、にーい、さーん」と返してくれます。
これで、非同期処理の順番を指定することが出来ました!
以上です!
おわりに
最後まで読んで頂きありがとうございました
どなたかの参考になれば幸いです