つくる 読み込み中の表示を出す
このレッスンで分かること
- 届く前と届いたあとで、画面を意識して描き分けます
- 切り替えを関数に名前を付けて分けておくと、読み込み直しが数行で済みます
届くまでの数百ミリ秒が、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 より前です。そうしておけば、読み込み中の表示にも新しい回数が反映されます。
手を動かす順番
- HTML に、読み込み中の表示と状態表示と読み込み直すボタンを足す
- 3 つの要素を
querySelectorで取る - 300 ミリ秒後に公開中の作品を返す関数を書く
- 読み込み中の画面と、届いたあとの画面に切り替える関数を 1 本ずつ書く
- 順番を決める
async functionを書き、最後に 1 回呼ぶ - ボタンのクリックで、その関数をもう一度呼ぶ
3 まで書いた時点でスピナーが回りっぱなしになります。それが正しい途中経過です。
うまく切り替わらないときは、次の順で見ていくと原因にたどり着けます。スピナーが一度も出ないなら、読み込み中にする処理が await より後ろにあります。回ったまま止まらないなら、resolve が呼ばれていないか、届いたあとの処理を呼び忘れています。カードは出るのに件数が出ないなら、状態表示の要素が取れていません。querySelector の結果が null になっていないか確かめてください。
課題
- 作品セクションに、読み込み中の表示 #works-loading (中に span.spinner) と、状態を出す #works-status と、読み込み直す #works-reload を足す
- fetchWorks() を作る。300 ミリ秒後に published が true の作品だけの配列で resolve する Promise を返す
- showLoading() で #works-loading から hidden を外し、カードと状態表示を空にする
- showLoaded(list) で #works-loading に hidden を付け、カードを描き、#works-status に「N 回目の読み込み / M 件」を出す
- loadWorks() を async function として作り、読み込んだ回数を数える。読み込んだ直後に 1 回呼び、#works-reload を押したらもう一度呼ぶ