跳至主要内容

經過非同步時空暫停、信鴿傳書、JSON 語言解讀與復活保險甲的重重修煉,本章將迎來 Phase 4 的終極試煉!我們將融會貫通 async/awaitfetchtry...catch...finally 與可選串連 ?.,串接真實世界 OpenWeather API,打造具備完整載入狀態與例外容錯的「異世界氣象觀測站」。

Day 25: 結業實戰:打造你的異世界氣象觀測站

本文同步分享於2026鐵人賽:JS 核心重構:勇者轉職傳說

📜 這裡的修煉規則

孩子,在踏上今日的領地前,先坐下來喝杯酒吧。 修煉的路很長,別急著奔跑,先聽聽這份卷軸裡的古老叮嚀。

我在每一站的盡頭都為你鋪設了 實戰演武場 CodePen。那不只是程式碼的拼湊,而是你在這場暴風雨中,試圖用邏輯點燃的一顆星火。 成功突圍後,別忘了帶著你的戰利品回到 QuestBoard 佈告欄。在那裡,你會發現自己從不孤單,公會的夥伴們都正舉杯等待你的歸來。

記住...

導師看重的從來不是你的劍法有多華麗,而是當你被邏輯擊潰、滿身泥濘後,依然選擇握緊理性的劍柄,再次向真相發起衝鋒的勇氣。


🏆 Phase 4 結業式 🏆

「孩子,抬起頭來。你已經不再是那個只會在公會大廳門口徘徊的新手了。」

過去這五天,你學會了如何暫停時空(Async/Await)、派送信鴿(Fetch)、解讀異世界語言(JSON)、啟動遠程偵測(?.),甚至穿上了復活保險甲(Try/Catch)。

這些碎片化的技能,今天將在你的手中凝結成一件真正的神器:「異世界氣象觀測站」。這是一個能跨越位面,與真實地球資料對接的強大工具。

準備好接受轉職前的最後一場試煉了嗎?


🛡️ 【公會大廳:實戰導讀】

「導師,我們今天真的要連到『真實的伺服器』嗎?萬一我寫錯了,會不會弄壞人家的牆壁?」

我笑著指向窗外的雷鳴。

「別擔心,孩子。我們會使用 OpenWeather 公會提供的免費頻道。你只需要申請一個專屬的 『通訊密鑰 (API KEY)』,就能換取全球城市的即時氣象。今天,沒有模擬資料,沒有導師的保護色。你寫下的每一行 fetch,都將真實地穿越海底電纜,從遠方的資料中心帶回情報。」


💡 【戰前講義:技術連招表】

⚔️ 終極連招組合技

在今天的專案中,你需要施展以下五大核心連招:

  1. 時空暫停 (async/await):確保你的觀測站不會因為等待網路傳輸而導致畫面卡死。
  2. 信鴿傳書 (fetch):對準 OpenWeather 氣象站端點發送 HTTP 請求。
  3. 防禦偵測 (?. & ??):有些小城鎮可能缺少「濕度」或「風速」資料,確保你的 UI 介面不會因為找不到屬性而直接崩潰。
  4. 復活保險甲 (try...catch...finally)
    • try:嘗試獲取氣候資訊並解析 JSON。
    • catch:如果使用者輸入了不存在的城市(例如地獄深淵),優雅地捕捉 404 錯誤並顯示警報。
    • finally:無論成功或失敗,保證關閉載入中的轉圈圈(Loading)動畫。
  5. 畫面具現化 (DOM Manipulation):將解讀完的氣溫、濕度與天氣圖示安全渲染至網頁面板。

🛡️ 【本日圖解心法:氣象觀測站架構】

🛖 營火叮嚀:導師的圖解心法

左側是你的觀測站介面 (UI),中間是身為氣象員的你 (JS),右側是遠方的氣象塔 (API Server)。你的工作就是:發送請求 ➔ 拿到包裹 ➔ 拆封檢查 ➔ 渲染到面板。

氣象觀測站架構圖


🛡️ 【實戰攻略:如何取得密鑰?】

🔑 通訊密鑰 (API Key) 注意事項
  1. 前往 OpenWeather 官方網站 註冊免費帳號。
  2. 進入帳號後台設定,找到 My API Keys 頁面複製專屬金鑰。
  3. 重要提示:新生成的 API Key 通常需要 1~2 小時 的伺服器同步時間才能正式生效。如果剛申請完成時呼叫 API 收到 401 Unauthorized 錯誤,請先喝杯咖啡稍作等待。

🛠️ 【職人手把手:氣象站建築步驟】

為了確保你不會在暴風雨中迷失方向,導師為你整理了五大建設階段:

步驟一:開啟對外門戶 (註冊與密鑰配置)

完成 OpenWeather 帳號註冊與金鑰申請。若金鑰尚未開通生效,可先使用練習專案提供的測試通道進行本地修煉,待金鑰生效後再行替換。

步驟二:搭建觀測站外殼 (HTML/CSS)

建立城市輸入框、查詢按鈕與氣象顯示看板。務必確認 searchBtncityInput 以及資料呈現區塊具備清晰唯一的 id,以便 JavaScript 精準選取。

步驟三:呼叫信鴿與時空暫停 (Fetch + Async)

fetchWeather 函式中運用 async/await 進行非同步等待,並以 try...catch...finally 建立全方位防護網,確保 Loading 狀態在 finally 區塊中百分之百被關閉。

步驟四:防禦解讀 (JSON & Optional Chaining)

將回應物件解析為 JSON 物件,並使用可選串連運算子(例如 data.main?.temp)與空值合併運算子(??)安全讀取數值,徹底杜絕 Cannot read properties of undefined 的潛在威脅。

步驟五:視覺具現化 (DOM Rendering)

將解析完成的攝氏溫度、體感溫度、濕度與天氣敘述更新至 DOM 元素中。最後進行邊界測試:搜尋一個「不存在的未知城市」,驗證 catch 區塊是否能正確攔截並彈出友善的「領地不存在」提示。


⚔️ 【戰術對抗:學長與學弟的代碼對決】

招式示範:完整異步氣象觀測核心

❌ 冒險學弟:裸奔派 (忽視例外與狀態卡死)

  • 負能量評級:🔴 查無城市直接白屏 / 🔴 轉圈圈動畫永不停歇
naive-weather.js
async function getWeather(city) {
const loading = document.getElementById("loading");
loading.style.display = "block";

// 毫無防護直接請求,若城市不存在或斷網將造成未捕獲異常
const res = await fetch(`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=YOUR_API_KEY&units=metric`);
const data = await res.json();

// 若 API 回傳 404,data.main 為 undefined,此行直接噴錯中斷
document.getElementById("temp").textContent = data.main.temp + " °C";
loading.style.display = "none";
}

✅ 勇者學長:職人派 (全防禦鏈結 + 狀態保證還原)

  • 利潤評級:🟢 穩健容錯 / 🟢 清晰的使用者回饋體驗
weather-app.js
async function getWeather(city) {
const loading = document.getElementById("loading");
const errorMsg = document.getElementById("error-msg");
const tempEl = document.getElementById("temp");

try {
loading.style.display = "block";
errorMsg.textContent = "";

const apiKey = "YOUR_API_KEY";
const res = await fetch(`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}&units=metric&lang=zh_tw`);

// 主動檢查 HTTP 回應狀態
if (!res.ok) {
if (res.status === 404) throw new Error("探測失敗:找不到該領地座標!");
throw new Error(`通訊異常 (狀態碼:${res.status})`);
}

const data = await res.json();

// 防禦讀取資料並渲染
const temp = data.main?.temp ?? "--";
const desc = data.weather?.[0]?.description ?? "未知氣候";

tempEl.textContent = `${temp} °C (${desc})`;
} catch (err) {
errorMsg.textContent = `📢 觀測警報:${err.message}`;
} finally {
// 關鍵!無論成功或失敗,必定關閉載入動畫
loading.style.display = "none";
}
}

🏆 【導師的通關證言】

🛖 營火叮嚀:導師的通關證言

恭喜你,勇敢的冒險者。

從今天起,你的代碼具備了「生命跳動」的感覺。它能與全世界互動,能處理失敗,能保護數據。

明天,我們不增加新技能。我們會停下來,學習如何將這些強大的邏輯「拆分與模組化 (Modules)」,為接下來的 終極職業轉職 做好最後的架構整建。

在此,我宣布你已正式通過「與外部世界連結」的修煉!


📝 【夥伴筆記:今日修煉精華】

這份筆記是你的隨身護身符,卡關時看一眼,真相就在裡面。

  • 真實 API 連線三要素:端點 URL、通訊協定(HTTP/HTTPS)、授權金鑰(API Key)。
  • 非同步防禦黃金結構:以 try 包裹 fetchres.json(),在 catch 提供降級 UI,並在 finally 確保狀態(如 Loading 動畫)完美復原。
  • HTTP 狀態主動防禦fetch 遇 404 / 500 不會自動 reject,須透過 if (!res.ok) throw new Error(...) 主動拋出錯誤導流至 catch
  • 深層物件防禦提取:使用可選串連運算子(data.main?.temp)與空值合併(??),避免因資料不全引發連鎖崩潰。

🎯 【實戰演武場】

⚔️ 任務鑑定條件:

  1. 完成 📜 結業任務 (CodePen)
  2. 將 CodePen 網址貼至 QuestBoard,並回填鑑定報告:
    • 初心者:觀測站竣工 (成就感發掘)
        1. 使用 async/await 成功獲取並解析 OpenWeather 即時資料。
        1. 將氣溫、濕度與天氣敘述正確渲染至 DOM 看板。
    • 冒險者:防禦全開 (理性挑戰)[⚡ 觀念辨析]
        1. 故意輸入不存在的城市(如「亞特蘭提斯」),確認畫面能優雅顯示錯誤訊息且 Loading 正常關閉。
        1. 檢視程式碼中是否全面使用 ?. 避免屬性讀取報錯。
  3. 任務完成後,你的名字將永遠標記在公會的英雄榜上!

📚 【圖書館卷軸與前後站連結】