JavascriptでのPromiseの操作
JavascriptにおいてPromise
は非常に興味深いトピックで、少し複雑なトピックでもあります。Promise
はJavascriptプログラミングにおいてよく利用されます。
JavascriptのPromisesとは何か?
Promise
は、非同期操作の操作が完了したとき,または失敗したときにその結果の値を返すオブジェクトです。つまり、Promise
は特定の時間間隔の後に何らかの値を返します。値は、resolve
またはreject
のいずれかです。
以下のコードを考えてみましょう
let promiseObj = new Promise(()=> 'some promise');
console.log(promiseObj);
/**
* the output will be Promise {<pending>} not 'some promise'
*/
ある時点で、Promiseは以下の3つの状態のいずれかになります。
- pending -Promiseが作成されたときの初期状態。
- fulfilled -Promiseが正常に実行されたときの状態。
- rejected -何らかのエラーまたは何らかの条件が原因でPromiseが失敗したときの状態。
const promise = new Promise((resolve, reject) => {
try{
setTimeout(() => {
resolve('resolved promise');
}, 5000);
}
catch (e) {
reject(e)
}
});
// this will print - 'resolved promise'
promise.then((val) => console.log(val))
上記のコードのsetTimeout関数は、5秒後に実行されます。したがって、promiseは5秒後にresolveされると言えます。その後、その promise.then((val) => console.log(val))
ブロックが実行され、resolved promise
の出力が返されます。
Promise
オブジェクトは、パラメータとしてexecutor関数を持ちます。
new Promise(executor_function)
executor関数は、resolve
かreject
かの2つのパラメータがあります。promiseが成功したときはresolve
を返し、executorメソッドの最初のパラメーターであるメソッドでそれを実行します。失敗の値を持つpromiseをresolveする場合は、executorメソッドの2番目のパラメーターであるreject
メソッドを使用します。
new Promise((resolve , reject)=>{
try{
resolve(/** resolve some suceess way over here */)
}catch (err){
/** reject if some error occured */
reject(err)
}
})
Promiseメゾット
-
Promise.all()
Promise.all()
メソッドは配列をパラメーターとして受け入れます。Promise.all()
で渡された配列内のすべてのPromises
がresolveまたはrejectされるのを待って、resolveされた新しい配列を返します。const promise1 = Promise.resolve(32); const promise2 = 1234; const promise3 = new Promise((resolve, reject)=>{ setTimeout(()=> 'resolve something',2000) }) Promise.all([promise1, promise2, promise3 ]).then( /** * will console the values after 2 seconds * [32, 1234, 'resolve something'] */ val => console.log(val) )
Promise.all
の問題は、1つのPromise
が失敗したり、拒否されたりした場合、Promise.all
全体が失敗して、それぞれのエラーが発生することです。そのため、Promise.all
を実行する際には注意が必要です。Promise.all
の利点は、並行してタスクを実行できることです。しかし、配列内のどのPromise
も失敗しないようにする必要があります。 -
Promise.allSettled()
Promise.allSettled
は、パラメータとして配列を受け取り、すべてのPromise
がresolve
するのを待ちます。実行されたPromise
は、reject
された値かresolve
された値のどちらかになります。Promise
が解決すると、resolve
されたのPromise
の配列を返します。解決済みのPromise
の場合、return オブジェクトは、status
フィールドをfulfill
として、value
フィールドをそのPromise
のresolve
された値として持ちます。reject
されたPromise
に対しては、return オブジェクトはrejected
としてステータスフィールドを持ちvalue
フィールドの代わりに、Promise
がreject
された理由を持つreason
フィールドを持ちます。const promise1 = Promise.resolve('resolved value'); const promise2 = 23; const promise3 = new Promise(function(resolve, reject) { setTimeout(reject, 100, 'i will be rejected'); }); Promise.allSettled([promise1, promise2, promise3]).then(function(values) { console.log(values); }); /** * * output for the above code: * * Array [ Object { status: "fulfilled", value: 'resolved value' }, * Object { status: "fulfilled", value: 23 }, * Object { status: "rejected", reason: "i will be rejected" } * ] * */
-
Promise.race()
Promise.race
は、パラメータとして配列を受け取り、最初にPromiseされたPromiseの値を返します。resolveしたPromiseは、resolveされるかrejectされるかのどちらかになります。rejectされた場合は、rejectされた最初のPromiseの理由を付けてrejectされます。const promiseMeApple = new Promise(function(resolve, reject) { setTimeout(resolve, 100, `🍎`); }); const promiseMeGrapes = new Promise(function(resolve, reject) { setTimeout(resolve, 300, `🍇`); }); Promise.race([promiseMeApple, promiseMeGrapes]).then(function(value) { //resolved value console.log(value); }); // expected output: "🍎"
-
Promise.resolve()
Promise.resolve
は、新しいPromise
が返す値をパラメータとして受け取り、resolveした値で新しいPromise
を返します。let melonPromise = Promise.resolve(`🍉`); /** will console log : [object Promise] */ console.log(melonPromise); /** * if u want to console the value of promise then use a callback * * This will print 🍉 as output */ melonPromise.then(val => console.log(val));
-
Promise.reject()
Promise.reject
は拒否される理由をパラメータとして受け取り、rejectされたPromise
をそのreason
とともに返す。let tomatoPromise = Promise.reject(`I don't like Tomatos 🍅 `); /** will console log : Promise {<rejected>: "I don't like Tomatos 🍅 "} */ console.log(tomatoPromise); /** * if u want to console the value of promise then use a callback * * This will print * * : Uncaught (in promise) I don't like Tomatos 🍅 * * as output */ tomatoPromise.then(val => console.log(val));
Application of promises
Promise
の最大のメリットは、タスクを並行して実行できることです。Promise
を使えば、タスクを同時に実行することができるので、時間を大幅に短縮することができます。
ここでは、async await
を使ってAPI呼び出しを行うことを考えてみましょう。
async function performingTwoApiCalls (){
const burgerData = await fetch('/get-api-call-for-burget-data');
const pizzaData = await fetch('/get-api-call-for-pizza-data');
/**
*
* some processing with the above data
*
*/
const combineBurgerAndPizzaData = [...burgerData, ...pizzaData];
}
上の例を見てみると、2回目のAPIコールは最初のAPIコールの終了を待たなければなりません。Promise
を使ってこれを行うより良い方法は以下の通りです。
function performingTwoApiCalls (){
const burgerPromise = Promise.resolve(fetch('/get-api-call-for-burget-data'));
const pizzaPromise = Promise.resolve(fetch('/get-api-call-for-pizza-data'));
Promise.all([ burgerPromise , pizzaPromise ])
.then((val)=>{
const burgerData = val[0];
const pizzaData = val[1];
const combineBurgerAndPizzaData = [...burgerData, ...pizzaData];
})
}
上記の例では、Promise.all
メソッドを用いて2つのAPIコールが非同期に実行され、resolve
された値を取得してさらに処理が行われます。