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された値を取得してさらに処理が行われます。