[Hero Of UnderGround 地下城] — 5F AQI 全台空氣指標儀表板
成果 & 程式碼
Introduction & 前言
超級菜鳥這次來挑戰第五層的BOSS了,這次必須串接API取的資料後Show在網頁上,對剛接觸JS不久以及根本沒碰過API的我是一大挑戰啊...
Summary & 摘要
由於JS地下城每個BOSS的弱點都不一樣,每一層都要由弱點去進行攻略,本次BOSS的弱點有三項。
第四點是自己加上的(笑
【特定技術】必須使用 AJAX 技術串接資料 API,不可直些寫死資料在變數上。
【特定技術】上方切換城市(高雄、台北)後,下方會切換該城市的各地區。
【解決問題】糟糕,BOSS 使用屏蔽魔法將 API 出處移除了,身為勇者的你必須查出 API 的下落,才能順利擊敗此 BOSS。什麼,你說會有 CORS 問題?嗯… 身為勇者的你,一定可以找各種服務來解決的,畢竟你是「勇者」嘛 (燦笑。
【書寫能力】請寫一篇 BLOG 來介紹你的挑戰過程,你攻略此 BOSS 的攻略過程心得,底層 XMLHttpRequest、Fetch API 的差異,使用 Promise 來優化 XMLHttpRequest JAX,探討 CORS 問題解決方案。
尋找API?
作為第一次尋找API的我很幸運的,收尋了關鍵字就出現了,一切都要感謝谷歌大神(跪
進入後只需要再收尋欄位輸入關鍵字,或者到下面的各種標籤點擊搜尋就能找到了!
關於CORS & XMLHttpRequest & Promise 優化相關
跨來源資源共用(Cross-Origin Resource Sharing (CORS))是一種使用額外 HTTP 標頭令目前瀏覽網站的使用者代理取得存取其他來源(網域)伺服器特定資源權限的機制。當使用者代理請求一個不是目前文件來源 — — 例如來自於不同網域(domain)、通訊協定(protocol)或通訊埠(port)的資源時,會建立一個跨來源 HTTP 請求(cross-origin HTTP request)。
這邊引用MDN Web docs的文章,簡單來說,因為安全考量,API端如果沒有開啟CORS的話,我們把做好的網頁發布到公開網站上,資料是沒辦法撈到的。
處理的方法有幾種,一種是透過後端,利用伺服器端程式來繞過此問題,但是必須自己架設一個伺服器,亦或者使用國外免費架設伺服器,但是這邊採取其他方式。
前人種樹後人乘涼
感謝各種前端大神的幫忙,像是pvt5r486大大的文章內就提到使用別人建立好的服務,例如這個:
但是這個方法我在使用上發現速度似乎載入的比較慢,有時還有撈不到資料的問題
最後我使用了另一種大神推薦的方法,那就是 Google App Script!
使用 Google Apps Script 做中繼點取得跨網域API資料
首先必須要有一個google帳號,然後進入雲端硬碟,點擊左上角新增,第一次會看不到 Google App Script 這個程式,必須點擊最下面的連結更多應用程式。
然後再裡面貼上一段程式碼:
1 | function doGet(e){ |
- 接著點下 發布 → 部署為網絡應用程式
部署方式為:部署的網址?參數名稱= API 網址
這邊這樣說我也是理解了大半天,我資質愚鈍呀…
簡單說 部署的網址? 不用理它參數名稱就是 url ,你只需要在後面輸入 url=API 網址,之後他會產出一組網址給你 把那組網址跟你的這串 url=API 網址 結合後就可以使用了。
就是這串啦~
留下這串網址之後,以後只要有API的問題,加上他就對啦。
這邊感謝Mandy大神還有prt5r486大神的文章
XMLHttpRequest 和 Fetch API 差異
一般Ajax指的就是XMLHttpRequest(XHR),而Fetch API 是基于 Promise 設計的,後面我們會提到 Promise。
有興趣可以點我看文章
XMLHttpRequest 本質上但並不是一個設計優良的 API: + 不符合關注分離(Separation of Concerns)的原則 + 配置和調用方式非常混亂 + 使用事件機制來跟蹤狀態變化 + 基於事件的異步模型沒有現代的 Promise,generator/yield,async/await 友好 。
Fetch API 旨在修正上述缺陷,它提供了與 HTTP 語義相同的 JS 語法,簡單來說,它引入了 fetch() 這個實用的方法來獲取網絡資源。
Promise 優化 XMLHttpRequest JAX
再接觸前端部分之前,有讀過PHP的書,裡面也有用到Ajax,在朋友的建議下,想著第一次串接API不如就直接學習AXIOS,因為他本身也有 Promise 功能了。
1 | function getapi() { |
有關Axios可以上官方GitHub查看
因為以前完全沒接觸過Ajax及Axios,在查看了各位大神的文章後,
Promise的架構大致如下。
1 | let promise = new Promise((resolve, reject) => { |
而白話一點就是可以理解成式子的可能為:
承諾 被兌現 (fulfilled)
→用 resolve() 來兌現
承諾 被打破 (rejected)
→用 reject() 來表示失敗
承諾 一直沒有回應 (pending)
→一直沒有回傳
而在這些承諾之後:
承諾被兌現 就 繼續做預定好的下一件事
使用 .then()
承諾被打破 就 根據這個原因去做對應的動作
使用 .catch(),或是 .then 的第二個參數
承諾 一直都沒有回應 就 繼續等下去
resolve() 運行 → .then 承諾被兌現
reject() 運行 → .catch 承諾失敗
然而因為我們使用 XMLHttpRequest() 取得結果會是字串,必須使用JSON.parse() 轉成 JSON 才能使用。
善用 filter() Method 點我前往
參考各位大神文章後,了解了基本方法如下:
1 | let arr = ['apple', 'banana', 'lemon', 'apple', 'watermelon', 'grape']; |
item — 當前是 arr 陣列中的哪一個值,如「apple」
index — 這個值在 arr 陣列中的索引,如「apple」的索引為 0
array — 這個陣列的內容
function* alldata() {
let* result = data.filter((*item*, *index*, *array*) => {
if ($.inArray(item.County, Country) == -1) {
Country.push(item.County); //判斷有無重複並放入縣市名稱
$('.select-box').append('<option>' + item.County + '</option>');
return true;
} else {
return false;
}
});
}
在 item 裡我們已經將所有資料分開了,方便我們過濾資料,而這邊我們使用if條件是判斷不讓相同縣市的資料出現第二次以上,因為這邊要把縣市放到上方的 Select 內的 Option 。
不得不說真的是常常用到組字串呢
下方的資料一樣使用 filter() 及 組字串方式,把各縣市的資料放上 div,造出一個一個的 div(誰叫我不會Vue呢TAT
jQuery.data() 方法點我
這邊值得一提,因為使用重組字串的方法,所以用到了 jQuery 的 data() ,而造出來的字,會被HTML自動翻成小寫,資質愚鈍如我花了大把時間再找為何我的onclick事件抓不到呢…
Conclusion & 結論
這系列的地下城真的幫助我 JS 成長了許多,每每覺得要卡關了,還是能慢慢爬文慢慢吸收,然後破關,我想最主要的還是邏輯部分,簡化自己的程式碼,另外在這次做API之前我根本毫無頭緒,這是很好的練習,也是我的第一次(羞
最後的最後一樣要加強的也是文筆部分,看各位大神都精簡扼要,我都還是露露長。雖然這只是剛開始寫 Blog 的第二篇廢文,還是要列出檢討的地方,然後朝下一關繼續加油,完畢。
JS
邏輯
文筆
體重
我的其他範例
Hero Of UnderGround — 1F Multiplicatio 九九乘法表
Hero Of UnderGround — 2F Clock 時鐘
Hero Of UnderGround — 3F Calculator 計算機
Hero Of UnderGround — 4F World Clock 各國時區
參考網站
- pvt5r486大神的Blog — 全台空氣指標攻略心得
- Mandy大神的Bolg — 利用google apps script做中繼點跨網域遠端取得api資料* * )* henry35208大神的鐵人邦 — Promise介紹
- axios的GitHub — axios
- camsong大神的GitHubg Bolg — 傳統Ajax已死,Fetch永生
- W3school 教學網站
- 行政院環保署資料開放平臺
- *巴哈姆特 舒壓用*