Promiseは、将来完了する可能性のある非同期処理を表すJavaScriptのオブジェクトです。「処理が完了したら結果を返します」という約束のようなものです。Promiseには次の3つの状態があります。
- Pending(保留): 初期状態。処理が完了も拒否もされていない状態。
- Fulfilled(完了): 処理が正常に完了した状態。
- Rejected(拒否): 処理が失敗した状態。
なぜPromiseを使う必要があるのか?
Promiseが登場する前は、非同期処理を扱うためにコールバック関数が使用されていました。しかし、コールバック関数をネストしていくと「コールバック地獄」と呼ばれる状態になり、コードが読みにくく、保守が困難になります。Promiseは、コードを明確で直線的に記述する方法を提供することで、この問題を解決し、非同期処理の管理とエラー処理を容易にします。
JavaScriptでPromiseを使用する方法
Promiseの作成
Promiseを作成するには、new Promise
を使用し、resolve
と reject
の2つの引数を持つexecutor関数を渡します。resolve
はPromiseが正常に完了したときに呼び出され、reject
はPromiseが拒否されたときに呼び出されます。
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve('成功!');
} else {
reject('失敗!');
}
}, 1000);
});
この例では、1秒後にPromiseが「成功!」という結果で完了するか、「失敗!」という理由で拒否されます。
.then()と.catch()で結果を処理する
Promiseから結果を受け取るには、.then()
と .catch()
メソッドを使用します。.then(onFulfilled)
はPromiseが完了したときに呼び出され、.catch(onRejected)
はPromiseが拒否されたときに呼び出されます。
promise
.then((result) => {
console.log(result); // "成功!"
})
.catch((error) => {
console.error(error); // "失敗!"
});
Promiseの連結 (Chaining)
.then()
内でPromiseを返すことで、複数のPromiseを連結できます。
firstPromise()
.then((result1) => {
return secondPromise(result1);
})
.then((result2) => {
console.log(result2);
})
.catch((error) => {
console.error(error);
});
Promise.allの使用
Promise.all
を使用すると、複数のPromiseを並列に実行し、すべてが完了したときに結果を取得できます。
const promise1 = fetchData1();
const promise2 = fetchData2();
Promise.all([promise1, promise2])
.then(([result1, result2]) => {
console.log(result1, result2);
})
.catch((error) => {
console.error(error);
});
.catch()
を使用して、常にエラーを処理してください。省略すると、エラーが検出されず、デバッグが困難な問題が発生する可能性があります。
ReactでのPromiseの使い方
Reactでは、API呼び出しなど、非同期処理を実行する必要があることがよくあります。Promiseを使用すると、これらのタスクを効率的に管理できます。
fetch APIとPromiseの併用
fetch
は、データをフェッチするためのJavaScriptに組み込まれたAPIであり、Promiseを返します。
fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => response.json())
.then((data) => {
console.log(data);
})
.catch((error) => {
console.error('エラー:', error);
});
この例では、https://jsonplaceholder.typicode.com/users
にあるAPIを呼び出して、ユーザーリストを取得しています。
コンポーネントでPromiseとuseEffectを使用する
import React, { useState, useEffect } from 'react';
function UserList() {
const [users, setUsers] = useState(null);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => response.json())
.then((data) => {
setUsers(data);
})
.catch((error) => {
console.error('エラー:', error);
});
}, []);
return (
<div>
{users ? (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
) : (
<div>読み込み中...</div>
)}
</div>
);
}
export default UserList;
- 依存関係配列が空の
[]
のuseEffect
は、コンポーネントがマウントされたときに一度だけ実行されます。 fetch
を使用してAPIを呼び出し、結果を受け取ったらusers
stateを更新します。
PromiseとAsync/Awaitの比較
Async/AwaitはPromiseに基づく新しい構文であり、コードを同期コードのように見せることで、可読性を向上させます。エラー処理には try...catch
を使用し、.then()
のネストを回避します。ただし、Async/Awaitを使用するには、Promiseをよく理解している必要があります。 Async/Awaitは、コードを同期的に見せ、読みやすくし、非同期処理を順番に実行する必要がある場合に使用します。 Promiseは、複数の非同期処理を同時に管理し、Promise.all
、Promise.race
などのメソッドを使用する必要がある場合に使用します。