# สัปดาห์ที่ 9: Asynchronous JavaScript

## 📋 Asynchronous คืออะไร?

ปกติแล้ว โปรแกรม JavaScript ทำงานทีละขั้นตอน (บรรทัดบน → บรรทัดล่าง)

```javascript
console.log("ข้อ 1");
console.log("ข้อ 2");
console.log("ข้อ 3");

// Output:
// ข้อ 1
// ข้อ 2
// ข้อ 3
```

แต่ถ้าเรา **เรียก API** คอมฯก็จะค้าง (freeze) 😱

**วิธีแก้:** ใช้ **Asynchronous** ให้คอมฯ "ทำอย่างอื่นไปก่อน" แล้วมากลับมาทีหลัง

---

## 🎯 ตัวอย่างง่ายๆ

### ❌ วิธีเก่า (block ทั้งหมด)

```javascript
console.log("1. เริ่มเลย");

// จำลองงานหนัก (ทำให้รอ)
let sum = 0;
for (let i = 0; i < 1000000000; i++) {
  sum += i;
}

console.log("2. จบแล้ว");
// UI คอมฯจะ "แข็ง" ขณะรอบนี้ 🥶
```

### ✅ วิธีใหม่ (asynchronous)

```javascript
console.log("1. เริ่มเลย");

setTimeout(() => {
  console.log("2. รอสักครู่แล้ว");
}, 2000); // รอ 2 วินาที

console.log("3. ไปต่อเลย UI ไม่แข็ง");

// Output:
// 1. เริ่มเลย
// 3. ไปต่อเลย UI ไม่แข็ง
// (รอ 2 วินาที)
// 2. รอสักครู่แล้ว
```

---

## 1️⃣ setTimeout - รอแล้วทำ

**ใช้เมื่อ:** เรากำหนดว่า "รอ X วินาที แล้วถึงทำ"

```javascript
// เริ่มต้น
setTimeout(() => {
  console.log("หลังจาก 3 วินาที จะทำ");
}, 3000); // 3000 milliseconds = 3 วินาที

// ยกเลิก
const timer = setTimeout(() => {
  console.log("ไม่จะทำ");
}, 5000);

clearTimeout(timer); // ยกเลิก
```

**ตัวอย่างจริง:**

```javascript
// ปุ่มส่งไป
button.addEventListener("click", () => {
  button.disabled = true;
  button.textContent = "กำลังส่ง...";

  // หลังจาก 2 วินาที ให้เปิดปุ่มอีกครั้ง
  setTimeout(() => {
    button.disabled = false;
    button.textContent = "ส่ง";
  }, 2000);
});
```

---

## 2️⃣ setInterval - ทำซ้ำๆ

**ใช้เมื่อ:** อยากให้งานทำซ้ำหลายๆ ครั้ง

```javascript
let count = 0;

const timer = setInterval(() => {
  count++;
  console.log(`นับครั้งที่ ${count}`);

  // หยุดเมื่อถึง 5
  if (count === 5) {
    clearInterval(timer);
    console.log("จบแล้ว!");
  }
}, 1000); // ทำทุกๆ 1 วินาที

// Output:
// นับครั้งที่ 1
// นับครั้งที่ 2
// นับครั้งที่ 3
// นับครั้งที่ 4
// นับครั้งที่ 5
// จบแล้ว!
```

**ตัวอย่างจริง: นาฬิกา**

```javascript
const hours = document.getElementById("hours");
const minutes = document.getElementById("minutes");
const seconds = document.getElementById("seconds");

setInterval(() => {
  const now = new Date();

  hours.textContent = now.getHours().toString().padStart(2, "0");
  minutes.textContent = now.getMinutes().toString().padStart(2, "0");
  seconds.textContent = now.getSeconds().toString().padStart(2, "0");
}, 1000); // อัปเดตทุกๆ วินาที
```

---

## 3️⃣ Promise - "สัญญา" ว่าจะส่งค่าให้

### 🤝 ทำให้เข้าใจแบบง่ายๆ กับตัวอย่างชีวิตจริง

**สมมติว่า:** คุณโทรหาร้านอาหารสั่งอาหาร

- ☎️ **คุณโทร** → ร้านอาหารสัญญาว่า "30 นาที อาหารจะเสร็จ"
- ⏳ **30 นาที ผ่านไป**
  - ✅ **สำเร็จ:** อาหารเสร็จแล้ว "สัญญาสำเร็จแล้ว!" → คุณเอาอาหารไป
  - ❌ **ล้มเหลว:** เกิดปัญหา "ขออภัย เกิด error!" → คุณอาจจะสั่งที่อื่น

**Promise ก็เหมือนแบบนี้:**

```javascript
// 📌 บรรทัด 1: สร้างสัญญา
const promise = new Promise((resolve, reject) => {
  // ↑ resolve = "เมื่อสำเร็จ ให้เรียกอันนี้"
  // ↑ reject = "เมื่อล้มเหลว ให้เรียกอันนี้"

  // 📌 บรรทัด 2: รอ 2 วินาที
  setTimeout(() => {
    // 📌 บรรทัด 3: หลังจาก 2 วินาที → ส่งข้อมูล (สำเร็จ)
    resolve("ได้ข้อมูลแล้ว!");
    // ↑ resolve() = "บอกว่า สัญญาสำเร็จ + ส่งข้อมูล"
  }, 2000); // 2000 millisecond = 2 วินาที
});

// 📌 บรรทัด 4: เตรียมรับผล
promise
  .then((result) => {
    // 📌 บรรทัด 5: ถ้า resolve ถูกเรียก → ทำอันนี้
    console.log("✅ สำเร็จ:", result); // Output: ✅ สำเร็จ: ได้ข้อมูลแล้ว!
  })
  .catch((error) => {
    // 📌 บรรทัด 6: ถ้า reject ถูกเรียก → ทำอันนี้
    console.error("❌ ล้มเหลว:", error);
  });
```

### 📊 อธิบายแต่ละส่วน

**1. `new Promise((resolve, reject) => { ... })`**

- `new Promise` = "สร้างสัญญา"
- `(resolve, reject)` = "ให้คุณเลือก: สำเร็จ หรือ ล้มเหลว"
- `resolve()` = "เรียกเวลาสำเร็จ" ✅
- `reject()` = "เรียกเวลาล้มเหลว" ❌

**2. `setTimeout(() => { ... }, 2000)`**

- รอ 2 วินาที แล้วจึงทำสิ่งข้างใน

**3. `resolve("ได้ข้อมูลแล้ว!")`**

- "สัญญาสำเร็จแล้ว และส่งข้อมูลนี้ไป"
- ข้อมูลนี้จะไป `.then()` ต่อได้

**4. `.then((result) => { ... })`**

- `then` = "เมื่อ resolve ถูกเรียก ให้ทำอันนี้"
- `result` = ข้อมูลที่ส่งมาจาก `resolve()`

**5. `.catch((error) => { ... })`**

- `catch` = "เมื่อ reject ถูกเรียก ให้ทำอันนี้"
- `error` = ข้อมูลที่ส่งมาจาก `reject()`

### 📊 ลำดับการทำงาน (ขั้นต่อขั้น)

```
⏱️  วินาทีที่ 0:
    1️⃣  สร้าง promise
    2️⃣  .then() อยู่ที่นี่ และรอ (ยังไม่ทำ)
    3️⃣  .catch() อยู่ที่นี่ และรอ (ยังไม่ทำ)

⏱️  วินาทีที่ 0-2:
    ⏳ setTimeout รออยู่... (ไม่ทำไรเลย)

⏱️  วินาทีที่ 2:
    4️⃣  setTimeout จบ → resolve() ถูกเรียก
    5️⃣  .then() ตื่นขึ้นมา "เอ! resolve ถูกเรียกแล้ว!"
    6️⃣  .then() ทำงาน → console.log("✅ สำเร็จ: ได้ข้อมูลแล้ว!")
    7️⃣  .catch() นอนหลับต่อไป (ไม่มี reject เรียก)

📤 Output ที่ได้:
✅ สำเร็จ: ได้ข้อมูลแล้ว!
```

### 🎯 ตัวอย่างที่ชัดเจนกว่า

**ตัวอย่าง 1: สำเร็จ**

```javascript
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("ได้ข้อมูลแล้ว");
  }, 1000);
});

promise.then((result) => {
  console.log(result); // "ได้ข้อมูลแล้ว" (หลังจาก 1 วินาที)
});
```

**ตัวอย่าง 2: ล้มเหลว**

```javascript
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("เกิด error!"); // ❌ สัญญาล้มเหลว
  }, 1000);
});

promise.catch((error) => {
  console.error(error); // "เกิด error!" (หลังจาก 1 วินาที)
});
```

**ตัวอย่าง 3: ตรวจสอบเงื่อนไข**

```javascript
function checkAge(age) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (age >= 18) {
        resolve("สามารถทำได้ มีอายุ " + age + " ปี");
      } else {
        reject("อายุไม่พอ มี " + age + " ปี");
      }
    }, 1000);
  });
}

// ถ้าอายุ >= 18 → .then()
checkAge(20).then((msg) => {
  console.log("✅ ", msg); // ✅ สามารถทำได้ มีอายุ 20 ปี
});

// ถ้าอายุ < 18 → .catch()
checkAge(15).catch((msg) => {
  console.error("❌ ", msg); // ❌ อายุไม่พอ มี 15 ปี
});
```

**ตัวอย่างจริง: จำลอง API**

```javascript
function getUser(userId) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (userId > 0) {
        resolve({ id: userId, name: "John", email: "john@example.com" });
      } else {
        reject("Invalid user ID");
      }
    }, 1000);
  });
}

getUser(1)
  .then((user) => {
    console.log("ได้ user:", user);
  })
  .catch((error) => {
    console.error("Error:", error);
  });
```

---

## 4️⃣ async/await - ง่ายกว่า

**เปรียบเทียบกับชีวิตจริง:**

- 📚 **โค้ดปกติ:** เรียงลำดับทีละบรรทัด
- ⏳ **Promise (.then):** ยุ่งมากกับ `.then()` เยอะๆ
- ✨ **async/await:** เขียนได้ง่ายๆ เหมือนเรียงลำดับปกติ แต่มี magic ที่ทำให้รอได้

**จริงๆ async/await คือ:**

> "วิธีเขียน Promise ที่ดูสวย สั้น และเข้าใจง่าย"

### 📊 เปรียบเทียบวิธี 3 แบบ

**วิธี 1: Promise with .then() (ยุ่ง)**

```javascript
function getUser(userId) {
  return fetch(`/api/users/${userId}`)
    .then((r) => r.json())
    .then((user) => {
      console.log("ได้ user:", user);
      return user;
    })
    .catch((error) => console.error("Error:", error));
}
```

**วิธี 2: async/await (สวยกว่า)**

```javascript
async function getUser(userId) {
  try {
    const response = await fetch(`/api/users/${userId}`);
    const user = await response.json();
    console.log("ได้ user:", user);
    return user;
  } catch (error) {
    console.error("Error:", error);
  }
}
```

### 🎯 ความแตกต่างอธิบายแบบง่าย

**Promise:** "ให้ฉันงาน แล้วฉันจะทำให้เสร็จ จบบรรทัดแล้ว" (ยังไม่จบ ต้องรอ then)

**async/await:** "รอ... ทีนี้ทำการต่อไป" (ดูเหมือนเขียนปกติ)

```javascript
// ❌ ต้องเปิด .then() หลายๆ ครั้ง
getUser(1)
  .then((user) => console.log(user))
  .then(() => getPost(1))
  .then((post) => console.log(post))
  .catch((err) => console.error(err));

// ✅ สวย: เขียนแบบเรียงลำดับปกติ
async function start() {
  try {
    const user = await getUser(1);
    console.log(user);

    const post = await getPost(1);
    console.log(post);
  } catch (err) {
    console.error(err);
  }
}

start();
```

### 🔑 สิ่งที่ต้องจำ

1. **async function** = ฟังก์ชั่นที่สามารถใช้ `await` ได้
2. **await** = "รอให้ Promise เสร็จสิ้น แล้วส่งค่ากลับมา"
3. **try/catch** = "ถ้าสำเร็จ try ถ้า error catch"

```javascript
// ตัวอย่าง: async function
async function doSomething() {
  // ❌ ผิด: สัญญาจะอยู่รอ
  const result = new Promise((resolve) => {
    setTimeout(() => resolve("เสร็จ!"), 2000);
  });

  // ✅ ถูก: รอให้เสร็จ แล้วเอาค่าจริง
  const result = await new Promise((resolve) => {
    setTimeout(() => resolve("เสร็จ!"), 2000);
  });

  console.log(result); // 'เสร็จ!'
}
```

---

## 💪 ตัวอย่างปฏิบัติจริง

### ตัวอย่าง 1: Countdown Timer

```javascript
function countdown(seconds) {
  return new Promise((resolve) => {
    let remaining = seconds;

    const timer = setInterval(() => {
      if (remaining > 0) {
        console.log(`${remaining}...`);
        remaining--;
      } else {
        console.log("หมดเวลา!");
        clearInterval(timer);
        resolve();
      }
    }, 1000);
  });
}

async function start() {
  console.log("เริ่ม countdown...");
  await countdown(5);
  console.log("จบแล้ว!");
}

start();

// Output:
// เริ่ม countdown...
// 5...
// 4...
// 3...
// 2...
// 1...
// หมดเวลา!
// จบแล้ว!
```

### ตัวอย่าง 2: ทำหลายอย่างพร้อมกัน

```javascript
function task1() {
  return new Promise((resolve) => {
    setTimeout(() => resolve("task 1 สำเร็จ"), 1000);
  });
}

function task2() {
  return new Promise((resolve) => {
    setTimeout(() => resolve("task 2 สำเร็จ"), 1000);
  });
}

async function doAll() {
  // ทำพร้อมกัน (ใช้เวลา ~1 วินาที)
  const [result1, result2] = await Promise.all([task1(), task2()]);

  console.log(result1); // task 1 สำเร็จ
  console.log(result2); // task 2 สำเร็จ
}

doAll();
```

---

## ⚠️ ผิดเรื่องไหน - แก้ยังไง

### ❌ ผิด: ลืม await

```javascript
async function getUser() {
  const user = getUserAPI(); // ❌ ลืม await
  console.log(user); // Promise ไม่ใช่ข้อมูล
}
```

### ✅ แก้:

```javascript
async function getUser() {
  const user = await getUserAPI(); // ✅ ใส่ await
  console.log(user); // ข้อมูลจริง
}
```

---

### ❌ ผิด: ลืม catch error

```javascript
async function getUser() {
  const user = await getUserAPI(); // ถ้า error? ไม่มีใครจัดการ!
  console.log(user);
}
```

### ✅ แก้:

```javascript
async function getUser() {
  try {
    const user = await getUserAPI();
    console.log(user);
  } catch (error) {
    console.error("Error:", error); // ✅ จับ error
  }
}
```

---

### ❌ ผิด: ใช้ await ในลูป (ช้า)

```javascript
async function getUsers() {
  const ids = [1, 2, 3, 4, 5];

  for (const id of ids) {
    const user = await getUserAPI(id); // รอทีละตัว ช้า!
    console.log(user);
  }
  // ใช้เวลา ~5 วินาที (1s × 5)
}
```

### ✅ แก้: ทำพร้อมกัน

```javascript
async function getUsers() {
  const ids = [1, 2, 3, 4, 5];

  // ทำพร้อมกันทั้งหมด
  const users = await Promise.all(ids.map((id) => getUserAPI(id)));

  console.log(users);
  // ใช้เวลา ~1 วินาที (ไม่ใช่ 5 วินาที)
}
```

---

## 🎯 Lab: Traffic Light Simulator

สร้าง HTML ที่มี 3 สีไฟ (🔴 🟡 🟢) ที่เปลี่ยนสีอัตโนมัติ:

- 🔴 Red: 3 วินาที
- 🟡 Yellow: 2 วินาที
- 🟢 Green: 3 วินาที
- แล้วกลับไป 🔴 ซ้ำไป

**Starter Code:**

```html
<!DOCTYPE html>
<html>
  <head>
    <title>Traffic Light</title>
    <style>
      .light {
        width: 80px;
        height: 80px;
        border-radius: 50%;
        margin: 20px;
        opacity: 0.3;
        transition: opacity 0.2s;
      }

      .light.active {
        opacity: 1;
      }

      .red {
        background: red;
      }
      .yellow {
        background: yellow;
      }
      .green {
        background: green;
      }
    </style>
  </head>
  <body>
    <div class="light red" id="red"></div>
    <div class="light yellow" id="yellow"></div>
    <div class="light green" id="green"></div>

    <script>
      // เขียน code ที่นี่

      // Step 1: สร้าง function ที่เปิดสี 1 สี (ใช้ setTimeout)
      // Step 2: สร้าง async function ที่เปิดสี ตามลำดับ
      // Step 3: เรียก function ใน loop
    </script>
  </body>
</html>
```

**Hints:**

```javascript
function showLight(colorId, duration) {
  return new Promise((resolve) => {
    const element = document.getElementById(colorId);

    // เปิดสี
    element.classList.add("active");

    // หลังจาก duration มิลลิวินาที ให้ปิดสี
    setTimeout(() => {
      element.classList.remove("active");
      resolve();
    }, duration);
  });
}

async function trafficLight() {
  while (true) {
    // ซ้ำไป
    await showLight("red", 3000);
    await showLight("yellow", 2000);
    await showLight("green", 3000);
  }
}

trafficLight(); // เริ่มต้น
```

---

## 📚 Reference

| คำ              | ความหมาย                           |
| --------------- | ---------------------------------- |
| **setTimeout**  | ให้โปรแกรมรอแล้วทำ 1 ครั้ง         |
| **setInterval** | ให้โปรแกรมรอแล้วทำซ้ำๆ             |
| **Promise**     | สัญญา "บางทีข้างหน้า" จะได้ข้อมูล  |
| **async**       | ฟังก์ชันที่ใช้ `await` ข้างใน      |
| **await**       | "รอให้ Promise เสร็จ แล้วถึงไปต่อ" |
| **resolve**     | สำเร็จ ส่งข้อมูล                   |
| **reject**      | ล้มเหลว ส่ง error                  |

---

## 🏁 Key Points

✅ Asynchronous = "ทำเป็นลำดับ ไม่บล็อก UI"  
✅ setTimeout/setInterval ใช้ง่าย  
✅ Promise คือสัญญา "ในอนาคต"  
✅ async/await = Promise แต่อ่านง่าย  
✅ **ห้ามลืม try/catch**  
✅ ทำหลายอย่างพร้อมกัน = Promise.all()

---

**Next:** สัปดาห์หน้า Fetch API (เรียก server จริงๆ)
