コース一覧
非同期JavaScript:API通信とモジュール
つくる 読み込み中の表示を出す

非同期JavaScript:API通信とモジュール

Promise と async/await、非同期エラー、HTTP/REST、fetch による GET、読み込み・成功・失敗の表示、モジュールの読み方を学ぶ全 19 レッスン(380 分)のコースです。最後は承認済みの読み取り専用 API から作品データを取得して表示します。POST はリクエストの組み立てまでで、外部サービスへの書き込みは行いません。

1
非同期処理
01. 同期と非同期15分
02. Promise をつくって返す20分
03. async と await20分
04. Promise.all で同時に待つ20分
05. 非同期のエラーを捕まえる20分
06. つくる 読み込み中の表示を出す30分
07. 第1章まとめクイズ10分
2
fetch で外のデータを使う
01. HTTP と REST の読みかた15分
02. fetch でデータを取る25分
03. 取ったデータを描画する25分
04. response.ok と失敗時の表示25分
05. POST のリクエストを組み立てる20分
06. つくる 作品データを API から読む30分
07. 第2章まとめクイズ10分
3
モジュールと総仕上げ
01. ファイルを分けるという考えかた15分
02. named export と default export15分
03. つくる ポートフォリオアプリを仕上げる40分
04. ここから先の学びかた15分
05. 第3章まとめクイズ10分

つくる 読み込み中の表示を出す

解説

このレッスンで分かること

  • 届く前と届いたあとで、画面を意識して描き分けます
  • 切り替えを関数に名前を付けて分けておくと、読み込み直しが数行で済みます

届くまでの数百ミリ秒が、0 件のページに見える

これまでの作品一覧は、works 配列が最初からそこにあったので、読み込んだ瞬間にカードが並びました。データが遅れて届くようになると、返事が来るまでの何百ミリ秒かは配列が空です。

そのあいだ何も出さないと、利用者には「作品が 0 件のサイト」に見えます。壊れているのか、読み込み中なのか、区別が付きません。今回はここを埋めます。決まりは次のとおりです。

  • 読み込み中は、回るスピナーと説明文を出す
  • 300 ミリ秒後に、公開中の作品だけがカードとして並ぶ
  • 何回目の読み込みで何件出したかを、状態表示に出す
  • ボタンを押したら、もう一度はじめからやり直す
状態画面に出るもの
読み込み中回るスピナーと説明文
届いたあと作品カードと、読み込み回数と件数

消さずに隠す

状態を表すのに、要素を作り直す必要はありません。CSS 側に .hidden { display: none; } を用意してあるので、クラスを付け外しするだけで足ります。

JavaScript

const notice = document.querySelector("#save-notice"); notice.classList.remove("hidden"); // 出す notice.classList.add("hidden"); // 隠す

remove() で要素ごと消してしまうと、二度と出せません。読み込み直したときにまた出したいので、要素は残したまま隠します。

遅れて届くデータのほうは、setTimeout を new Promise で包んで作ります。中身を確定させたい行で resolve を呼ぶ、という形です。

JavaScript

function fetchBio() { return new Promise(function (resolve) { setTimeout(function () { resolve("Web エンジニアを目指しています"); }, 300); }); }

この形にしておくと、あとで中身を本物の通信に取り替えるとき、呼ぶ側を 1 文字も直さずに済みます。非同期の処理を関数の内側に閉じ込めておく利点がここに出ます。

順番を決める関数は 1 本だけにする

画面を触る処理は、読み込み中に切り替えるものと、届いたあとに切り替えるもので分けます。そのうえで、順番を決める async function を 1 本置きます。中身は次の形になります。

JavaScript

async function save() { showSaving(); // await より前に置く const text = await fetchBio(); showSaved(text); }

読むと何が起きるかが 3 行で分かります。読み込み中にして、待ち、届いた形にする、です。切り替えを 1 か所に集めておくと、ボタンを押したときの処理はこの関数を呼び直すだけで済みます。

何回目の読み込みかを数える変数は、関数の外に let で置きます。押すたびに数値そのものを別の数値に入れ替えるので、const では書けません。数えるのは await より前です。そうしておけば、読み込み中の表示にも新しい回数が反映されます。

手を動かす順番

  1. HTML に、読み込み中の表示と状態表示と読み込み直すボタンを足す
  2. 3 つの要素を querySelector で取る
  3. 300 ミリ秒後に公開中の作品を返す関数を書く
  4. 読み込み中の画面と、届いたあとの画面に切り替える関数を 1 本ずつ書く
  5. 順番を決める async function を書き、最後に 1 回呼ぶ
  6. ボタンのクリックで、その関数をもう一度呼ぶ

3 まで書いた時点でスピナーが回りっぱなしになります。それが正しい途中経過です。

うまく切り替わらないときは、次の順で見ていくと原因にたどり着けます。スピナーが一度も出ないなら、読み込み中にする処理が await より後ろにあります。回ったまま止まらないなら、resolve が呼ばれていないか、届いたあとの処理を呼び忘れています。カードは出るのに件数が出ないなら、状態表示の要素が取れていません。querySelector の結果が null になっていないか確かめてください。

課題

  1. 作品セクションに、読み込み中の表示 #works-loading (中に span.spinner) と、状態を出す #works-status と、読み込み直す #works-reload を足す
  2. fetchWorks() を作る。300 ミリ秒後に published が true の作品だけの配列で resolve する Promise を返す
  3. showLoading() で #works-loading から hidden を外し、カードと状態表示を空にする
  4. showLoaded(list) で #works-loading に hidden を付け、カードを描き、#works-status に「N 回目の読み込み / M 件」を出す
  5. loadWorks() を async function として作り、読み込んだ回数を数える。読み込んだ直後に 1 回呼び、#works-reload を押したらもう一度呼ぶ

ヒント

CSS には .hidden `{ display: none; }` と .spinner が用意してあります。classList.add("hidden") と classList.remove("hidden") で出し入れしてください

読み込み中に切り替える処理は await より前の行に置きます。あとに置くと、届いてから読み込み中にすることになります

状態の文は「1 回目の読み込み / 4 件」の形です。回数の変数は押すたびに増えるので const ではなく let で持ちます

index.html
style.css
script.js
プレビュー

できているか

  • 読み込み中の表示 #works-loading がある
  • 遅れて届いた公開中の作品が 4 件並ぶ
  • 届いたあとは #works-loading に hidden が付いて隠れる
  • #works-status に 1 回目の読み込みと件数が出る
  • #works-reload を押すと 2 回目の読み込みが走って作品が並び直す
エディタを読み込んでいます