やさしいReact入門⑥

React

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を返す

コメント

タイトルとURLをコピーしました