Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hwweek8 #14

Merged
merged 3 commits into from Aug 18, 2020
Merged

Hwweek8 #14

merged 3 commits into from Aug 18, 2020

Conversation

ericcch24
Copy link
Collaborator

助教安安,有關作業二的 Javascript 的部分,我在看完老師的參考範例影片之後才知道可以用 callback 函式的方法寫,所以將我原先寫的部分修改成現在作業交出去的樣子。
但因為我原本絞盡腦汁寫出來的版本的功能跑出來完全一樣(底下已附上程式碼),也不覺得有什麼特別冗長迂迴的地方(除了一開始取前五名遊戲那邊)。且因為目前還體會不到使用 callback 函式的優點,加上在看完範例影片又研究了超級久才理解其中的邏輯,就忍不住會想說到底是不是有必要用到 callback 函式,因此想麻煩助教幫我看我原先這樣的做法與老師範例方法相比有什麼缺點,非常感謝!

<body>
  <nav class="navbar">
    <div class="wrapper">
      <div class="navbar__topic">
        Twitch Top Games
      </div>
      <ul class="navbar__list">
        <li><a target="_blank" class="first"></a></li>
        <li><a target="_blank" class="second"></a></li>
        <li><a target="_blank" class="third"></a></li>
        <li><a target="_blank" class="fourth"></a></li>
        <li><a target="_blank" class="fifth"></a></li>
      </ul>
    </div>
  </nav>
  <div class="game-page">
    <div class="wrapper">
      <div class="game-page__topic">
        Click Top Game
      </div>
      <div class="game-page__desc">
        Top 20 popular live streams sorted by current viewers
      </div>
      <div class='stream'>
      </div>
    </div>
  </div>
  <script src="week8hw2.js"></script>
</body>
const request = new XMLHttpRequest();
request.open('GET', 'https://api.twitch.tv/kraken/games/top', true);
request.setRequestHeader('Client-ID', '1oymoviz1aa1vi91cj12n1nisqs5ay');
request.setRequestHeader('Accept', 'application/vnd.twitchtv.v5+json');
request.onload = () => {
  if (request.status >= 200 && request.status < 400) {
    const data = JSON.parse(request.response);
    const first = document.querySelector('.first');
    const second = document.querySelector('.second');
    const third = document.querySelector('.third');
    const fourth = document.querySelector('.fourth');
    const fifth = document.querySelector('.fifth');
    first.innerText = `${data.top[0].game.name}`;
    second.innerText = `${data.top[1].game.name}`;
    third.innerText = `${data.top[2].game.name}`;
    fourth.innerText = `${data.top[3].game.name}`;
    fifth.innerText = `${data.top[4].game.name}`;
  } 
}
request.send();


function addEmptyBox() {
  const box = document.createElement('div');
  box.classList.add('stream__box__empty');
  document.querySelector('.stream').appendChild(box);
}


function rank(num) {
  const xhr = new XMLHttpRequest();
  const data = JSON.parse(request.response);
  const container = document.querySelector('.stream');
  xhr.open('GET', 'https://api.twitch.tv/kraken/streams/?game=' + encodeURIComponent(data.top[num].game.name), true);
  xhr.setRequestHeader('Client-ID', '1oymoviz1aa1vi91cj12n1nisqs5ay');
  xhr.setRequestHeader('Accept', 'application/vnd.twitchtv.v5+json');
  xhr.onload = () => {
    if (xhr.status >= 200 && xhr.status < 400) {
      const topLive = JSON.parse(xhr.response);
      const topic = document.querySelector('.game-page__topic');
      topic.innerText = `${data.top[num].game.name}`;
      for (let i = 0; i < 20; i += 1) {
        const div = document.createElement('div');
        div.classList.add('stream__box');
        div.innerHTML = `
        <img class="picture" src="${topLive.streams[i].preview.medium}"></img>
        <div class="user">
          <img class="avatar" src="${topLive.streams[i].channel.logo}"></img>
          <div class="word">
            <div class="content">${topLive.streams[i].channel.status}</div>
            <div class="name">${topLive.streams[i].channel.name}</div>
          </div>
        </div>
        `
        container.appendChild(div);
      }
      addEmptyBox();
      addEmptyBox();
    }
  }
  xhr.send();
}


function clickGame(stringClass, num) {
  document
  .querySelector(stringClass)
  .addEventListener('click', () => {
    document.querySelector('.stream').innerHTML = '';
    rank(num);
  });
}

clickGame('.first', 0);
clickGame('.second', 1);
clickGame('.third', 2);
clickGame('.fourth', 3);
clickGame('.fifth', 4);

@ClayGao ClayGao merged commit 241961d into master Aug 18, 2020
} else if (data.prize === 'NONE') {
cover.classList.add('none');
content.innerText = '銘謝惠顧';
}
Copy link
Contributor

@ClayGao ClayGao Aug 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

這邊也可以使用 switch case 來做,但同學這樣寫也 OK

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我會再嘗試看看,謝謝助教!

request.setRequestHeader('Accept', 'application/vnd.twitchtv.v5+json');
request.onload = () => {
if (request.status >= 200 && request.status < 400) {
cb(JSON.parse(request.response));
Copy link
Contributor

@ClayGao ClayGao Aug 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

直接將 JSON.parse(request.response) 帶入 callback function 中,如果後端回傳的資料為空或者非 JSON 格式,程式就掛了

可以回想 week4 時是怎麼去預防這樣的問題的

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

沒考慮到特殊情況,感謝助教!

@ClayGao
Copy link
Contributor

ClayGao commented Aug 18, 2020

且因為目前還體會不到使用 callback 函式的優點,加上在看完範例影片又研究了超級久才理解其中的邏輯,就忍不住會想說到底是不是有必要用到 callback 函式,因此想麻煩助教幫我看我原先這樣的做法與老師範例方法相比有什麼缺點,非常感謝!

其實以老師的範例來說,他做的事情其實你在 week4 就已經做過了,就以你 week4 hw1 的作業舉例:

const request = require('request');

const API_URL = 'https://lidemy-book-store.herokuapp.com';

request(`${API_URL}/books?_limit=10`, (error, response, body) => {
  let list;
  try {
    list = JSON.parse(body);
    // eslint-disable-next-line
  } catch (error) {
    console.error('抓取失敗', error);
    return;
  }

  for (let i = 0; i < list.length; i += 1) {
    console.log(`${list[i].id} ${list[i].name}`);
  }
});

其中 request 的第二個參數,就是當我拿到 response 的時候要怎麼處理,這邊想必你已經懂了

承上,假如今天我開給你一個需求,就是我要你寫一個函式,當我呼叫這個函式的時候,他要以上述的範例幫我執行 request(),除此之外,當我拿到 response 時,我不要只做你上面那一種的處理,我要能額外做另外幾種處理

先解決第一個問題:包成函式。這時候你可能很直覺的就寫成下列:

const request = require('request');

function requestSomething () {
  const API_URL = "https://lidemy-book-store.herokuapp.com";
  request(`${API_URL}/books?_limit=10`, (error, response, body) => {
    let list;
    try {
      list = JSON.parse(body);
      // eslint-disable-next-line
    } catch (error) {
      console.error("抓取失敗", error);
      return;
    }

    for (let i = 0; i < list.length; i += 1) {
      console.log(`${list[i].id} ${list[i].name}`);
    }
  });
}

requestSomething()

但由於要能對 response 做不同處理,所以函式內的 request 的第二個參數 - 也就是 callback function,當我拿到 response 時所要執行的副程式,就可以當作參數,如此一來,不管我要做哪種處理,就傳不同的函式進來就好了。於是我們改寫成以下:

const request = require('request');

function requestSomething (cb) {
  const API_URL = "https://lidemy-book-store.herokuapp.com";
  request(`${API_URL}/books?_limit=10`, cb);
}

這樣的話,只要我執行 requestSomething 時,於參數帶入不同的函式,我就可以針對 response 做不同的處理了:

const request = require('request');

function requestSomething (cb) {
  const API_URL = "https://lidemy-book-store.herokuapp.com";
  request(`${API_URL}/books?_limit=10`, cb);
}

// 其中一種處理方式,後面可以根據想做不同的處理帶入不同的函式為參數
requestSomething((error, response, body) => {
  let list;
  try {
    list = JSON.parse(body);
    // eslint-disable-next-line
  } catch (error) {
    console.error("抓取失敗", error);
    return;
  }

  for (let i = 0; i < list.length; i += 1) {
    console.log(`${list[i].id} ${list[i].name}`);
  }
});

其實老師的範例大概就是這樣。以這份作業的要求來說,我們要對 response 的處理大概就是逐個安插到頁面上,這沒有問題。

但如果今天我不只要這樣做,我作業換個題目的話,那我就只要改我當作參數帶進去的那個函式就好了,負責發 request 拿資料的部分就可以不用改變,因為他只是負責拿資料而已。

所以這個概念就比較符合老師之前提過的重用性,但我忘記是哪一週了。你應該有發現,getStreamsgetGames 的泛用性很高。想像今天你要建一個新的專案,要跟 Twitch 拿資料,你會發現就算直接複製這兩個函式到新的專案也可以使用

大概就是這樣,如果有說錯也請指正我 XD

@ClayGao ClayGao deleted the hwweek8 branch August 18, 2020 18:02
@ericcch24
Copy link
Collaborator Author

原來如此,這樣我就有理解 callback function 的方便了,感謝助教的詳細易懂解說!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants