【もりけん塾】JavaScript課題6 -DOM構築とPromiseオブジェクト②-

JavaScript

今日は、もりけん塾のJavaScript課題6 を終えて学んだことをアウトプットしていきます。

こんにちは。Webコーダーのはるです。

現在、所属している「もりけん塾」でハンズオン課題 に取り組み、レビューをいただいています。

今日は、課題6 についてアウトプットをしていきます。
(前回までのアウトプットは、こちらです。)

●課題6で学んだこと

・setTimeout()メソッド
・アロー関数の{ }を省略する
・処理ごとにコードを分ける
・promise.then()は新しいpromiseオブジェクトを返す

【もりけん塾】JavaScript課題6で学んだこと まとめ

今回、取り組んだ課題はこちらです。


(もりけん先生のJavaScriptハンズオン課題より)

setTimeout()メソッド

3秒後にpromiseのresolve()を呼ぶためにはどうしたら良いのだろうと調べた時に、setTimeout()メソッドが出てきました。

使用したことがなかったので調べました。

MDNには

時間切れになると関数または指定されたコードの断片を実行するタイマーを設定します。

とあります。

.setTimeout(function[, delay]);
delayに遅延させたいミリ秒、実行したい関数をfunctionに書きます。

 

delayは省略することもできますが、省略すると0の値が入り、直ちに実行(= なるべく早く実行)されます。

今回は、このfunctionにpromiseのresolve()を入れて、delayに3000(3秒後)を入れれば実現できそうだな〜とわかりました。

アロー関数の{ }を省略する

前回の課題5のコードにsetTimeout()メソッドを追加すると、なんだか見にくいなぁと感じたのでアロー関数を調べ直して{ } を省略してみることにしました。

最初に書いたsetTimeoutの部分↓

const promise = new Promise(resolve => {
  setTimeout(() => resolve(attributes), 3000);
}).then(省略

MDNの”もっともシンプルなアロー関数に段階的に変える”という節が勉強になりました。

setTimeout(() => { 
  resolve(attributes), 3000)
});

↓

setTimeout(() => resolve(attributes), 3000);
resolve()を覆っていた{ } を省略すると少しシンプルなコードになりました。

 

中括弧{ }は、関数の本文が複数行の場合は省略することができないので、今後処理が増えて複数行になるときは{ }とreturnを追記する必要が出てきます。

アロー関数について理解を深めることができました。

処理ごとにコードを分ける

これまで調べたことをふまえて、最初にPRしたコードがこちらです。

const attributes = [
 { to: "bookmark.html", img: "1.png", alt: "画像1", text: "ブックマーク" },
 { to: "message.html", img: "2.png", alt: "画像2", text: "メッセージ" }
];

const ul = document.getElementById("js-lists");

const fragment = document.createDocumentFragment();

const promise = new Promise(resolve => {
 setTimeout(() => resolve(attributes), 3000);
}).then(attributes => {
 attributes.forEach(attribute => {
  const li = document.createElement("li");
  const anchor = document.createElement("a");
  const img = document.createElement("img");

  anchor.textContent = attribute.text;
  anchor.href = `/${attribute.to}`;
  img.src = attribute.img;
  img.alt = attribute.alt;

  li.appendChild(anchor).insertAdjacentElement("afterbegin", img);
  fragment.appendChild(li);
 });
 ul.appendChild(fragment);
});
なんかpromiseのところが、ごちゃごちゃしていて見にくいなぁ😨と思いつつPR。

 

塾生のさえさん(@sae_prog) から「処理ごとにコードを分ける」ことをレビューしていただきました!

・3 秒後に resolve で実行される処理
・ノードを作成・追加する処理
の2つのプロセスに分けてコードを修正してみます!

 

修正後のPromiseの部分からのコード↓

//3 秒後に resolve で実行される処理
const promise = new Promise(resolve => {
 setTimeout(() => resolve(attributes), 3000);
});

//ノードを作成・追加する処理
promise.then(attributes => {
 attributes.forEach(attribute => {
  const li = document.createElement("li");
  const anchor = document.createElement("a");
  const img = document.createElement("img");

  anchor.textContent = attribute.text;
  anchor.href = `/${attribute.to}`;
  img.src = attribute.img;
  img.alt = attribute.alt;

  li.appendChild(anchor).insertAdjacentElement("afterbegin", img);
  fragment.appendChild(li);
 });
 ul.appendChild(fragment);
});
実際にはコメントアウトは書いていませんが、わかりやすいように入れてみました。
このように処理でコードを分けると、とても読みやすいコードになりました!
全部の処理を一度に書こうとしていたから見にくかったのですね。。
とても勉強になりました!ありがとうございます!

promise.then()は新しいpromiseオブジェクトを返す

さらに、塾生のもなかさん(@ruby443n)からレビューをいただきました!

解決されたPromiseの値を得て→ノードの作成・追加をする以下のコードで

promise.then(attributes => { 
  attributes.forEach(attribute => {
then()に引数として使用している”attributes”は、すでに冒頭で配列を定義している変数名なので、同じものを使わない方が良いとレビューいただきました。
//冒頭で定義した変数attributes
const attributes = [
  { to: "bookmark.html", img: "1.png", alt: "画像1", text: "ブックマーク" },
  { to: "message.html", img: "2.png", alt: "画像2", text: "メッセージ" } 
];
then()に入るコールバック関数の引数には、resolve()で解決された値 = attributesと定義した配列が入るのですが、ここに理解の甘い部分がありました。

 

最初に定義したpromiseに格納された値は、resolve(attributes)で解決された値として受け取った配列です。

次にチェーンで繋げたthen()メソッドは、最初のPromiseとは全く異なる新しいPromiseオブジェクトを返す、とMDNにありました。

これは同じ配列ではあるけれど、別の扱いをした方が良いはずだ。。しかもよくよく考えたら、同じ変数名を使用してしまうと、せっかくresolve()で配列の値を受け取った意味がない。。と気づいた。

修正コードは以下です↓

const attributes = [
 { to: "bookmark.html", img: "1.png", alt: "画像1", text: "ブックマーク" },
 { to: "message.html", img: "2.png", alt: "画像2", text: "メッセージ" }
];

const ul = document.getElementById("js-lists");

const fragment = document.createDocumentFragment();

const promise = new Promise(resolve => {
 setTimeout(() => resolve(attributes), 3000);
});

promise.then(values => {
 values.forEach(value => {
  const li = document.createElement("li");
  const anchor = document.createElement("a");
  const img = document.createElement("img");

  anchor.textContent = value.text;
  anchor.href = `/${value.to}`;
  img.src = value.img;
  img.alt = value.alt;

  li.appendChild(anchor).insertAdjacentElement("afterbegin", img);
  fragment.appendChild(li);
 });
 ul.appendChild(fragment);
});

valuesに修正しました。みなさんどんな名前をつけているんだろう・・・?

今回は、このコードでApproveをいただきました。

//

学習に使用している本は、もりけん先生推奨の”JavaScript本格入門”です。

あとがき

お忙しい時間を割いて課題を確認してくださった塾生のさえさん(@sae_prog)・もなかさん(@ruby443n)ありがとうございました!!

私の課題のリポジトリはこちらから確認できます↓

 

理解の曖昧だったアロー関数や、コールバック関数、then()メソッドについて調べることができた課題でした!

今日は以上です。

//

【もりけん塾で勉強しています】

もりけん先生(@terrace_tec)のHPはこちら