18: Fetch API & LocalStorage
เชื่อมต่อโลกกว้าง ดึงข้อมูลจริงจาก Server และเก็บความจำไว้ไม่ให้หายไปเมื่อปิดเว็บ
1. พนักงานรับส่งข้อมูล: Fetch API
fetch() คือคำสั่งในหน้าเว็บที่ใช้ ส่ง Request ไปขอข้อมูลจาก Server อื่น ๆ (API) กลับมาใช้งาน ซึ่งกระบวนการนี้ต้องใช้เวลาเดินทางผ่าน Network จึงต้องใช้ async / await เข้ามาช่วยเสมอ
ขั้นตอนการใช้ Fetch
await fetch(url): รอให้พนักงานเดินทางไปเอา "กล่องพัสดุ" กลับมาก่อนawait response.json(): รอแกะกล่องพัสดุ แล้วแปลงข้อมูลข้างในให้อ่านออกเป็น Object (JSON)
async function getPokemon() {
try {
// 1. ส่งพนักงานไปขอข้อมูล Pikachu (รอจนกว่าจะกลับมา)
let response = await fetch("https://pokeapi.co/api/v2/pokemon/pikachu");
// 2. แกะกล่องข้อมูล แปลงเป็น JS Object
let data = await response.json();
console.log("ชื่อ:", data.name);
console.log("น้ำหนัก:", data.weight);
console.log("รูปภาพ:", data.sprites.front_default);
} catch (error) {
console.error("ติดต่อ Server ไม่สำเร็จ:", error);
}
}
2. กระเป๋าเก็บของของ Web Browser: LocalStorage
ปกติเวลาที่รีเฟรชหน้าเว็บ หรือปิดคอมพิวเตอร์ ข้อมูลในตัวแปร JavaScript จะหายวับไปหมด แต่ localStorage คือพื้นที่เก็บข้อมูลพิเศษใน Web Browser ที่ ปิดคอมคอมพิวเตอร์เปิดใหม่ ข้อมูลก็ยังคงอยู่
กฎเหล็กของ LocalStorage
เก็บได้เฉพาะ ข้อความ (String) เท่านั้น ถ้าจะเก็บ Array หรือ Object ต้องแปลงร่างมันก่อนด้วย JSON.stringify() และตอนดึงออกมาใช้ต้องแปลงกลับด้วย JSON.parse()
let myFav = { name: "Pikachu" };
// 1. แปลง Object เป็น String
let stringData = JSON.stringify(myFav);
// 2. เก็บลงกระเป๋า ตั้งชื่อว่า "fav_mon"
localStorage.setItem("fav_mon", stringData);
// 1. หยิบของตามชื่อป้าย
let data = localStorage.getItem("fav_mon");
if (data !== null) {
// 2. แปลงกลับเป็น Object
let myFav = JSON.parse(data);
console.log(myFav.name);
}
// ท่าที่ 1: เลือกลบแค่บางรายการ
localStorage.removeItem("fav_mon");
// ท่าที่ 2: ล้างบาง! ลบทุกอย่างของเว็บนี้
// (ใช้ด้วยความระมัดระวัง)
localStorage.clear();
LocalStorage vs Cookie
ทั้งคู่ใช้เก็บข้อมูลใน Browser เหมือนกัน แต่เกิดมาเพื่อหน้าที่ต่างกัน:
- 🎒 LocalStorage คือ "กระเป๋าส่วนตัว": จุของได้เยอะ เก็บไว้ดูคนเดียว ฝั่ง Server จะไม่รู้ว่าในกระเป๋ามีอะไรบ้าง (จนกว่าจะเขียนโค้ดหยิบส่งไปให้)
- 🏷️ Cookie คือ "ป้ายห้อยคอ": เขียนได้นิดเดียว แต่ทุกครั้งที่โหลดเว็บหรือดึง API ตัว Web Browser จะ "แนบป้ายนี้ส่งไปให้ Server อ่านอัตโนมัติ" เสมอ
| คุณสมบัติ | 🎒 LocalStorage | 🏷️ Cookie |
|---|---|---|
| ขนาดความจุ | ใหญ่ (~5 - 10 MB) | เล็กมาก (~4 KB) |
| การแนบไป Server | ไม่ส่งไปอัตโนมัติ ข้อมูลอยู่แค่ในเครื่อง (โหลดเว็บไว ไม่เปลืองเน็ต) | ส่งไปอัตโนมัติ ทุกครั้งที่โหลดหน้าเว็บ หรือดึงข้อมูล |
| วันหมดอายุ | ไม่มี (อยู่จนกว่าจะเขียนโค้ดสั่งลบ หรือผู้ใช้กด Clear เอง) | ตั้งเวลาได้ (ถ้าไม่ตั้ง ปิดเบราว์เซอร์ปุ๊บหายปั๊บ) |
| ความปลอดภัย | โดนดึงผ่าน JS ได้ง่าย ห้ามเก็บรหัสผ่านหรือข้อมูลลับเด็ดขาด |
ปลอดภัยกว่า ตั้ง HttpOnly ป้องกันไม่ให้ JS แอบอ่านได้ |
| เหมาะสำหรับ | ตั้งค่าเว็บ (Dark Mode), ตะกร้าสินค้าชั่วคราว, แคชข้อมูลลดการดึง API | ระบบ Login (Session ID), เก็บประวัติติดตามพฤติกรรม (Tracking) |
เก็บแยกกันตาม Domain (เว็บไซต์)
Browser จะสร้างห้องเก็บของแยกให้แต่ละเว็บไซต์อย่างเด็ดขาด ข้อมูลที่เก็บไว้ใน youtube.com จะไม่สามารถถูกแอบอ่านหรือลบโดย facebook.com ได้
การความยินยอม (Consent)
แม้ในแง่เทคนิค Browser จะไม่เด้งหน้าต่างมาขออนุญาตผู้ใช้ แต่ ในทางกฎหมาย (PDPA) ถือว่า LocalStorage เทียบเท่า Cookie
📌 ฟังก์ชันพื้นฐาน (เช่น Dark mode): เก็บได้เลย ไม่ต้องขอ
📌 ใช้ติดตามตัว (Tracking/User ID): ต้องทำแบนเนอร์ให้กดยอมรับก่อนรันโค้ด
Workshop: สภาพอากาศ Real-time
ทดลองดึงอุณหภูมิปัจจุบันของ กรุงเทพมหานคร จาก Public API (Open-Meteo)
Requirements:
- สร้างปุ่มสำหรับโหลดข้อมูลสภาพอากาศ เมื่อคลิกที่ปุ่ม ให้ดึงข้อมูลจาก API
- พิกัดของขอนแก่น คือ (Lat 16.4322, Lon 102.8236) ให้ใช้ URL
https://api.open-meteo.com/v1/forecast?latitude=16.4322&longitude=102.8236¤t_weather=trueสำหรับดึงข้อมูลสภาพอากาศของขอนแก่น () - ข้อมูลเวลา สามารถใช้
new Date("2026-02-21T13:45" + "Z").toLocaleTimeString('th-TH')เพื่อแปลงเป็นเวลาไทย - เมื่อได้ข้อมูลจาก API ให้แสดงผลใน div
<div id="weatherResult">
<h6 class="text-muted text-uppercase fw-bold mb-1">Khonkaen, Thailand</h6>
<div class="display-3 fw-bold text-dark mb-0">
<span id="tempValue">--</span><span class="fs-1 text-muted">°C</span>
</div>
<p class="small text-muted mt-2 mb-0">อัปเดตล่าสุด: <span id="timeValue">--</span></p>
</div>
Practice Mission: สมุดภาพโปเกมอนส่วนตัว
สถานการณ์:
คุณคือนักผจญภัยที่กำลังรวบรวมรายชื่อโปเกมอน ให้สร้างระบบที่พิมพ์ชื่อโปเกมอน (ภาษาอังกฤษ) เพื่อดึงข้อมูลมาแสดงผล และเมื่อกดปุ่ม "บันทึกลงกระเป๋า" ให้เก็บชื่อโปเกมอนนั้นลง localStorage เพื่อให้รีเฟรชหน้าเว็บแล้วรายชื่อที่เคยเก็บไว้ยังอยู่ครบ
กระเป๋าเก็บโปเกมอน
Requirements:
- Fetch: เมื่อกดค้นหา ให้ใช้ URL
https://pokeapi.co/api/v2/pokemon/{ชื่อที่พิมพ์} - Render: ถ้าเจอ ให้แสดงภาพ
data.sprites.front_defaultและสร้างปุ่ม "บันทึก" - Render: ถ้าไม่เจอ ให้แสดงข้อความว่าไม่พบโปเกมอนที่ค้นหา
- Save: เมื่อกดบันทึก ให้อ่าน Array เก่าจาก
localStorage(ถ้ามี) จับชื่อนี้ยัดใส่ (Push) แล้ว Save ทับลงไปใหม่ (อย่าลืม JSON.stringify) - Load: สร้างฟังก์ชัน
loadFavorites()ให้ทำงานทันทีที่เปิดเว็บ เพื่อดึงข้อมูลจาก LocalStorage มาแสดงเป็น<li>ทันที