JavaScriptの非同期処理をやさしく理解する|Promiseとthenの基本
JavaScriptを書いていると、こんなコードを見かけることがあります。
fetch("https://example.com/api/users")
.then(response => response.json())
.then(data => {
console.log(data);
});
Reactを勉強していると、特によく登場するコードです。
しかし、JavaScriptを始めたばかりだと、
fetchって何?.then()って何?responseってどこから来たの?.then()が2回あるのはなぜ?
と、分からないことが一気に出てきます。
「.then()って何をしているんだ……?」
となりやすいポイントだと思います。
この記事では、
- 非同期処理とは何か
- Promiseとは何か
.then()とは何かfetch()とは何か- なぜ
.then()をつなげるのか
を、実際にコードを書きながらやさしく解説します。
まずは普通のJavaScriptから考えてみよう
いきなりfetchを見ると難しく感じるので、まずは普通の処理から考えてみましょう。
例えば、次のコードです。
const name = "太郎";
console.log(name);
console.log("処理終了");
このコードを実行すると、
太郎
処理終了
と表示されます。
これは、
① nameに「太郎」を入れる
↓
② nameを表示する
↓
③ 「処理終了」を表示する
という順番で処理されています。
このように、コードを書いた順番に処理が進んでいくことを、ざっくり同期処理と呼びます。
ポイント
同期処理では、基本的に「上から順番に処理されていく」
非同期処理とは?
では、次のような処理を考えてみましょう。
サーバーにデータをください!
サーバーにお願いすると、すぐに返事が返ってくるとは限りません。
例えば、
ブラウザ
↓
「ユーザー一覧ください」
↓
サーバー
↓
処理中……
↓
ユーザー一覧を返す
となります。
この間、ブラウザがずっと何もできない状態になってしまうのはよくない。
そこでJavaScriptでは、
時間のかかる処理が終わるのを待っている間に、別の処理を進める
という仕組みがあります。
これが非同期処理です。
わかりやすくイメージすると……
「時間のかかる処理をお願いしたら、その処理が終わるまでJavaScriptが全部止まる」のではなく、
「その処理を進めてもらっている間に、別のことを進められる」
というのが非同期処理です。
まずはsetTimeoutで体験してみよう
非同期処理を理解するために、まずsetTimeout()を使ってみましょう。
実際に手を動かしながら、演習する方はまずこちら(5分で設定できます)も合わせて見てください!
次のコードを書いてみてください。
console.log("① 開始");
setTimeout(() => {
console.log("② 3秒後");
}, 3000);
console.log("③ 終了");
実行すると、
① 開始
③ 終了
② 3秒後
となります。
「あれ?」と思うかもしれません。
コードは、
console.log("① 開始");
setTimeout(() => {
console.log("② 3秒後");
}, 3000);
console.log("③ 終了");
なので、
①
②
③
の順番になりそうですよね。
しかし実際には、
①
③
②
となります。
なぜ②が最後なのか?
setTimeout()は、
「3秒後にこの処理を実行してください」
とJavaScriptにお願いしています。
そのため、3秒待っている間に、
console.log("③ 終了");
が実行されます。
イメージすると、
① 開始
↓
「3秒後に②を実行してね」
↓
③ 終了
↓
3秒経過
↓
② 3秒後
となっています。
これが非同期処理の基本的なイメージです。
非同期処理では、「時間のかかる処理を開始したからといって、必ずしもそこで処理が止まるわけではない」ということがポイントです。
Promiseとは?
ここまでで、JavaScriptの非同期処理についてイメージできてきたかなと思います。
ここから、最初に登場した
fetch("https://example.com/api/users")
.then(response => response.json())
.then(data => {
console.log(data);
});
というコードにつながっていきます。
ここで登場する重要な言葉がPromise(プロミス)です。
Promiseを一言で表すなら、
「非同期処理が、将来どうなったのかを表す仕組み」
例えば、サーバーに「ユーザー一覧をください」とお願いした場合、
「今すぐ結果はありません。
でも、処理が終わったら結果を渡します」
という状態をPromiseで表現できます。
Promiseには大きく、
- 処理中
- 成功
- 失敗
という状態があります。
ここが今回の重要ポイント
fetch()のような非同期処理では、すぐに結果が返ってくるとは限りません。
その「将来返ってくる結果」を扱うために、Promiseが登場します。
.then()とは何をしているの?
では、いよいよ最初に出てきた.then()を見ていきましょう。
例えば、
promise.then(() => {
console.log("処理が終わりました");
});
というコードがあったとします。
.then()は簡単に言うと、
「Promiseの処理が成功したら、この処理を実行してね」
という意味です。
つまり、
非同期処理を開始
↓
Promise
↓
処理が成功
↓
.then()の中の処理を実行
という流れになります。
fetch()と.then()をつなげてみよう
ここまで理解できたら、最初に登場したコードが少し見やすくなってきます。
fetch("https://example.com/api/users")
.then(response => response.json())
.then(data => {
console.log(data);
});
まずfetch()は、指定したURLへHTTPリクエストを送信するためのJavaScriptの機能です。
例えば、
fetch("https://example.com/api/users")
と書くと、
「このURLからデータを取得してください」
という処理を開始します。
そしてfetch()は、結果をPromiseとして返します。
なので、.then()をつなげることで、
fetch()
↓
「処理が成功したら次の処理をしてね」
↓
.then()
という流れを作ることができます。
なぜ.then()が2回あるの?
ここが少し分かりにくいところかもしれませんね。
fetch("https://example.com/api/users")
.then(response => response.json())
.then(data => {
console.log(data);
});
まず最初の.then()では、サーバーから返ってきたレスポンスを扱います。
.then(response => response.json())
ここでresponse.json()を実行すると、レスポンスの本文をJSONとして読み取るための処理が始まります。JSONの読み取りが完了すると、その結果を返す Promise を返します。
そのため、JSONとして読み取った結果を、次の .then() で受け取ることができます。
.then(data => {
console.log(data);
});
このdataには、JSONとして読み取られたデータが入っています。
つまり全体としては、
fetch()
↓
サーバーへリクエスト
↓
レスポンスを受け取る
↓
response.json()
↓
JSONとしてデータを読み取る
↓
dataとして次の.then()へ
↓
console.log(data)
という流れになっています。
「.then()が2回ある」のではなく、「非同期処理を順番につないでいる」と考えると分かりやすいです。
最初の.then()でレスポンスを処理し、その結果を次の.then()へ渡しています。
今回のまとめ
今回は、JavaScriptの非同期処理を理解するために、
- 同期処理
- 非同期処理
- Promise
.then()fetch()
について学びました。
最初に見たコードも、今なら意味が見えてくるのではないでしょうか。
fetch("https://example.com/api/users")
.then(response => response.json())
.then(data => {
console.log(data);
});
このコードは、ざっくり言えば、
① fetchでデータを取得する
↓
② データが返ってきたらresponseを受け取る
↓
③ response.json()でJSONとして読み取る
↓
④ 読み取ったデータをdataとして受け取る
↓
⑤ dataを使って処理する
という流れになっています。
非同期処理 → 時間のかかる処理を待っている間も、別の処理を進められる
Promise → 非同期処理の結果を扱うための仕組み
.then() → Promiseの処理が成功した後に実行する処理を登録する
fetch() → HTTPリクエストを行い、Promiseを返す





コメント