สวัสดีครับ! วันนี้ผมจะมาสอนเทคนิคสำคัญที่ทุกคนควรรู้เมื่อทำงานกับ API นั่นก็คือ การยกเลิกคำขอ หรือ Cancel Request ครับ
เคยไหมครับที่กดปุ่มค้นหาแล้วรอนานมาก แล้วอยากกดยกเลิก? หรือเผลอกดซ้ำหลายครั้งจนเกิดปัญหา? บทความนี้จะแก้ปัญหานี้ให้หมดเลยครับ
ทำไมต้องยกเลิกคำขอ API?
ลองนึกภาพว่าคุณกำลังสร้างแอปที่ดึงข้อมูลจาก API ของ HolySheep AI แต่ข้อมูลใหญ่มากจนใช้เวลานาน หรือผู้ใช้กดย้ายหน้าไปอีกหน้าแล้ว คำขอเดิมก็ยังทำงานต่อ สิ้นเปลืองทรัพยากรเครื่องโดยใช่เหตุ
ปัญหาที่จะเกิดขึ้น:
- ผู้ใช้ได้รับข้อมูลเก่าที่ไม่เกี่ยวข้องแล้ว
- เซิร์ฟเวอร์ทำงานโดยไม่จำเป็น เสียค่าใช้จ่าย
- เบราว์เซอร์อาจค้างหรือช้าลง
- เกิดสภาวะ Memory Leak หรือรั่วไหลของหน่วยความจำ
AbortController คืออะไร?
AbortController คือเครื่องมือที่มาพร้อมกับเบราว์เซอร์ทุกตัวในปัจจุบัน (Chrome, Firefox, Safari, Edge) ช่วยให้เราสั่งยกเลิกคำขอ HTTP ได้เมื่อต้องการ
วิธีทำงานง่ายมาก:
- สร้าง Controller - คล้ายกับการเปิดรีโมทควบคุม
- ส่ง Signal ไปกับคำขอ - บอกว่าคำขอนี้มีใครสามารถยกเลิกได้
- เรียก abort() เมื่อต้องการยกเลิก - กดปุ่มยกเลิก!
เริ่มต้นใช้งาน AbortController ทีละขั้นตอน
ขั้นตอนที่ 1: สร้าง AbortController
ก่อนอื่นเราต้องสร้าง Object ที่ชื่อ AbortController ขึ้นมาก่อน ง่ายมากครับ:
// สร้าง AbortController ใหม่
const controller = new AbortController();
เมื่อสร้างแล้ว เราจะได้ controller.signal ซึ่งเป็น "สัญญาณ" ที่จะส่งไปกับคำขอ และ controller.abort() ซึ่งเป็นฟังก์ชันสำหรับสั่งยกเลิก
ขั้นตอนที่ 2: ส่ง signal ไปกับคำขอ API
ต่อไปเราจะนำ signal ไปใช้กับ fetch โดยเพิ่ม option ที่ชื่อ signal ดูตัวอย่างนี้ครับ:
// กำหนด URL ของ API
const url = 'https://api.holysheep.ai/v1/chat/completions';
// กำหนดข้อมูลที่จะส่ง
const data = {
model: 'gpt-4.1',
messages: [
{ role: 'user', content: 'สวัสดีชาวโลก' }
]
};
// สร้าง AbortController
const controller = new AbortController();
// ส่งคำขอพร้อม signal
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_HOLYSHEEP_API_KEY'
},
body: JSON.stringify(data),
signal: controller.signal // ← บรรทัดสำคัญ!
})
.then(response => response.json())
.then(result => console.log('ผลลัพธ์:', result))
.catch(error => {
if (error.name === 'AbortError') {
console.log('คำขอถูกยกเลิกแล้ว');
} else {
console.log('เกิดข้อผิดพลาด:', error);
}
});
ขั้นตอนที่ 3: สร้างปุ่มยกเลิก
ต่อไปเราจะสร้างปุ่มให้ผู้ใช้กดยกเลิกได้ และตั้งเวลายกเลิกอัตโนมัติหลัง 10 วินาที:
<!-- สร้างปุ่มใน HTML -->
<button id="btnSend">ส่งคำขอ</button>
<button id="btnCancel">ยกเลิก</button>
<div id="result"></div>
<script>
// กำหนด URL และข้อมูล
const url = 'https://api.holysheep.ai/v1/chat/completions';
const apiKey = 'YOUR_HOLYSHEEP_API_KEY';
let controller; // ตัวแปรเก็บ Controller
// ฟังก์ชันส่งคำขอ
async function sendRequest() {
controller = new AbortController();
const resultDiv = document.getElementById('result');
try {
resultDiv.innerHTML = 'กำลังโหลด...';
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': Bearer ${apiKey}
},
body: JSON.stringify({
model: 'gpt-4.1',
messages: [
{ role: 'user', content: 'เล่าเรื่องตลกขำๆ สักเรื่อง' }
]
}),
signal: controller.signal
});
const data = await response.json();
resultDiv.innerHTML = <strong>ผลลัพธ์:</strong> ${data.choices[0].message.content};
} catch (error) {
if (error.name === 'AbortError') {
resultDiv.innerHTML = '❌ คำขอถูกยกเลิกแล้ว';
} else {
resultDiv.innerHTML = ❌ เกิดข้อผิดพลาด: ${error.message};
}
}
}
// ฟังก์ชันยกเลิก
function cancelRequest() {
if (controller) {
controller.abort();
console.log('สั่งยกเลิกคำขอแล้ว');
}
}
// ตั้งเวลายกเลิกอัตโนมัติหลัง 10 วินาที
const timeoutId = setTimeout(() => {
cancelRequest();
}, 10000);
// ผูกปุ่มกับฟังก์ชัน
document.getElementById('btnSend').addEventListener('click', () => {
clearTimeout(timeoutId); // ยกเลิก timeout เดิมถ้ามี
sendRequest();
});
document.getElementById('btnCancel').addEventListener('click', () => {
clearTimeout(timeoutId); // ยกเลิก timeout ก่อน
cancelRequest();
});
</script>
ประยุกต์ใช้กับ Search Box จริงๆ
ตัวอย่างที่ใช้บ่อยที่สุดคือ Search Box ที่ผู้ใช้พิมพ์แล้วระบบค้นหาอัตโนมัติ เราต้องยกเลิกคำขอเก่าทุกครั้งที่ผู้ใช้พิมพ์ใหม่:
<!-- HTML สำหรับ Search Box -->
<input type="text" id="searchInput" placeholder="พิมพ์คำค้นหา...">
<div id="searchResults"></div>
<script>
const searchInput = document.getElementById('searchInput');
const searchResults = document.getElementById('searchResults');
let searchController; // เก็บ AbortController
searchInput.addEventListener('input', async (event) => {
const query = event.target.value.trim();
// ถ้าไม่มีข้อความ ไม่ต้องทำอะไร
if (!query) {
searchResults.innerHTML = '';
return;
}
// ยกเลิกคำขอเดิมก่อนเสมอ
if (searchController) {
searchController.abort();
console.log('ยกเลิกคำขอเก่าแล้ว');
}
// สร้าง AbortController ใหม่
searchController = new AbortController();
searchResults.innerHTML = '🔍 กำลังค้นหา...';
try {
// จำลองการเรียก API (แทนที่ด้วย API จริงของคุณ)
await new Promise(resolve => setTimeout(resolve, 1000));
// ส่งคำขอจริง (ใช้ HolySheep API)
/*
const response = await fetch(
'https://api.holysheep.ai/v1/chat/completions',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_HOLYSHEEP_API_KEY'
},
body: JSON.stringify({
model: 'gpt-4.1',
messages: [
{
role: 'user',
content: ค้นหาข้อมูลเกี่ยวกับ: ${query}
}
]
}),
signal: searchController.signal
}
);
const data = await response.json();
searchResults.innerHTML = data.choices[0].message.content;
*/
// ผลลัพธ์จำลอง
searchResults.innerHTML = 📋 ผลการค้นหา: "${query}" - พบ 5 รายการ;
} catch (error) {
if (error.name === 'AbortError') {
console.log('ข้ามผลลัพธ์เก่าแล้ว');
} else {
searchResults.innerHTML = ❌ เกิดข้อผิดพลาด: ${error.message};
}
}
});
</script>
หลักการสำคัญของตัวอย่างนี้คือ: ทุกครั้งที่พิมพ์ใหม่ ให้ยกเลิกคำขอเก่าก่อน นี่จะช่วยประหยัดทรัพยากรและทำให้แอปทำงานเร็วขึ้นมาก
ใช้ AbortController กับ axios
ถ้าโปรเจกต์ของคุณใช้ axios ซึ่งเป็น Library ยอดนิยมสำหรับเรียก API ก็มีวิธีง่ายๆ ครับ:
// ติดตั้ง axios ก่อน: npm install axios
// สร้าง Cancel Token แบบ axios
const controller = new AbortController();
const signal = controller.signal;
// ส่งคำขอด้วย axios
axios.post(
'https://api.holysheep.ai/v1/chat/completions',
{
model: 'gpt-4.1',
messages: [
{ role: 'user', content: 'ทักทายฉันหน่อย' }
]
},
{
headers: {
'Authorization': 'Bearer YOUR_HOLYSHEEP_API_KEY'
},
signal: signal // หรือ cancelToken: axios.CancelToken.source().token
}
)
.then(response => {
console.log('สำเร็จ:', response.data);
})
.catch(error => {
if (axios.isCancel(error)) {
console.log('คำขอถูกยกเลิกแล้ว');
} else {
console.log('เกิดข้อผิดพลาด:', error.message);
}
});
// ยกเลิกคำขอเมื่อต้องการ
// controller.abort();
รวมทุกอย่างเป็น Hook สำหรับ React
ถ้าใช้ React การสร้าง Hook สำหรับจัดการคำขอที่ยกเลิกได้จะช่วยให้โค้ดสะอาดมาก:
// useApiRequest.js - Custom Hook สำหรับ React
import { useState, useEffect, useRef } from 'react';
export function useApiRequest() {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const controllerRef = useRef(null);
const sendRequest = async (url, options = {}) => {
// ยกเลิกคำขอเก่าถ้ามี
if (controllerRef.current) {
controllerRef.current.abort();
}
// สร้าง AbortController ใหม่
controllerRef.current = new AbortController();
setLoading(true);
setError(null);
try {
const response = await fetch(url, {
...options,
signal: controllerRef.current.signal
});
const data = await response.json();
setLoading(false);
return data;
} catch (err) {
if (err.name === 'AbortError') {
console.log('คำขอถูกยกเลิก');
setError('CANCELLED');
} else {
setError(err.message);
}
setLoading(false);
return null;
}
};
const cancel = () => {
if (controllerRef.current) {
controllerRef.current.abort();
}
};
// ยกเลิกเมื่อ Component ถูกลบออก
useEffect(() => {
return () => {
if (controllerRef.current) {
controllerRef.current.abort();
}
};
}, []);
return { sendRequest, cancel, loading, error };
}
// วิธีใช้ใน Component:
// const { sendRequest, cancel, loading, error } = useApiRequest();
//
// const handleSubmit = async () => {
// const data = await sendRequest(
// 'https://api.holysheep.ai/v1/chat/completions',
// {
// method: 'POST',
// headers: {
// 'Authorization': 'Bearer YOUR_HOLYSHEEP_API_KEY'
// },
// body: JSON.stringify({ /* ... */ })
// }
// );
// };
ข้อผิดพลาดที่พบบ่อยและวิธีแก้ไข
กรณีที่ 1: ยกเลิกแล้วแต่ still ได้รับ Error อื่น
ปัญหา: หลังจาก abort แล้ว catch block จับได้แต่เป็น Error ปกติไม่ใช่ AbortError
// ❌ วิธีผิด - ไม่ตรวจสอบชื่อ Error
.catch(error => {
console.log('เกิดข้อผิดพลาด:', error); // จะแสดง AbortError ด้วย
});
// ✅ วิธีถูก - ตรวจสอบชื่อ Error ก่อน
.catch(error => {
if (error.name === 'AbortError') {
console.log('คำขอถูกยกเลิกโดยผู้ใช้');
// จัดการกรณียกเลิกที่นี่
} else {
console.log('เกิดข้อผิดพลาดจริง:', error.message);
// จัดการ Error อื่นๆ ที่นี่
}
});
// หรือใช้ instanceOf
.catch(error => {
if (error instanceof DOMException && error.name === 'AbortError') {
console.log('ยกเลิกแล้ว ไม่ต้องทำอะไร');
} else {
throw error; // Re-throw Error อื่นๆ
}
});
กรณีที่ 2: ยกเลิกคำขอเดียวแต่ยกเลิกหมดทุกคำขอ
ปัญหา: ใช้ Controller เดียวกันกับหลายคำขอ พอ abort ก็ยกเลิกหมด
// ❌ วิธีผิด - ใช้ Controller เดียวกัน
const controller = new AbortController();
Promise.all([
fetch(url1, { signal: controller.signal }),
fetch(url2, { signal: controller.signal }),
fetch(url3, { signal: controller.signal }),
]);
controller.abort(); // ยกเลิกทั้ง 3 คำขอ!
// ✅ วิธีถูก - สร้าง Controller แยกสำหรับแต่ละคำขอ
const controllers = [];
const request1 = fetch(url1, {
signal: (controllers[0] = new AbortController()).signal
});
const request2 = fetch(url2, {
signal: (controllers[1] = new AbortController()).signal
});
const request3 = fetch(url3, {
signal: (controllers[2] = new AbortController()).signal
});
// ยกเลิกเฉพาะ request2
controllers[1].abort();
// หรือถ้าต้องการยกเลิกพร้อมกันทั้งหมด
controllers.forEach(c => c.abort());
กรณีที่ 3: Memory Leak เพราะไม่ยกเลิกเมื่อ Component ถูกลบ
ปัญหา: ผู้ใช้ออกจากหน้าแล้วแต่คำขอยังทำงานต่อ เกิด Memory Leak
// ❌ วิธีผิด - ไม่มีการ cleanup
function MyComponent() {
const [data, setData] = useState(null);
const loadData = async () => {
const controller = new AbortController();
const response = await fetch(url, { signal: controller.signal });
const result = await response.json();
setData(result);
};
return <div>{data}</div>;
}
// ✅ วิธีถูก - ใช้ useEffect cleanup
function MyComponent() {
const [data, setData] = useState(null);
useEffect(() => {
const controller = new AbortController();
const loadData = async () => {
try {
const response = await fetch(url, { signal: controller.signal });
const result = await response.json();
setData(result);
} catch (error) {
if (error.name !== 'AbortError') {
console.error(error);
}
}
};
loadData();
// ✅ Cleanup - ยกเลิกเมื่อ Component ถูกลบ
return () => {
controller.abort();
};
}, []);
return <div>{data}</div>;
}
// สำหรับ React with Custom Hook (อีกวิธี)
function useAbortController() {
const controllerRef = useRef(null);
useEffect(() => {
return () => {
if (controllerRef.current) {
controllerRef.current.abort();
}
};
}, []);
return controllerRef;
}
กรณีที่ 4: ส่ง API Key ไม่ถูกต้อง
ปัญหา: ได้รับ Error 401 Unauthorized เพราะวิธีส่ง API Key ผิด
// ❌ วิธีผิด - ส่ง API Key ใน URL หรือผิด format
fetch('https://api.holysheep.ai/v1/chat/completions?key=YOUR_KEY');
fetch(url, {
headers: { 'api-key': apiKey } // ชื่อ Header ผิด!
});
// ✅ วิธีถูก - ส่ง Bearer Token ใน Authorization Header
const response = await fetch('https://api.holysheep.ai/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': Bearer ${apiKey} // ต้องมี "Bearer " นำหน้า!
},
body: JSON.stringify({
model: 'gpt-4.1',
messages: [
{ role: 'user', content: 'สวัสดี' }
]
}),
signal: controller.signal
});
const data = await response.json();
สรุป
วันนี้เราได้เรียนรู้วิธีใช้ AbortController เพื่อยกเลิกคำขอ API กันแล้วครับ สิ่งสำคัญที่ต้องจำคือ:
- สร้าง AbortController ก่อนส่งคำขอ
- ส่ง signal ไปกับ fetch options
- เรียก abort() เมื่อต้องการยกเลิก
- ตรวจสอบ error.name === 'AbortError' ใน catch block
- อย่าลืม cleanup เมื่อ Component ถูกลบ
การใช้ AbortController อย่างถูกต้องจะช่วยให้แอปพลิเคชันของคุณทำงานเร็วขึ้น ประหยัดทรัพยากร และให้ประสบการณ์ที่ดีกับผู้ใช้ครับ
แนะนำ HolySheep AI
ถ้าคุณกำลังมองหาผู้ให้บริการ AI API ที่มีความเร็วสูงและราคาประหยัด HolySheep AI เป็นตัวเลือกที่ยอดเยี่ยมครับ:
- 💰 อัตราแลกเปลี่ยนพิเศษ: ¥1=$1 ประหยัดมากกว่า 85%
- ⚡ ความเร็ว: 延迟ต่ำกว่า 50 มิลลิวินาที
- 💳 ชำระเงินง่าย: รองรับ WeChat และ Alipay
- 🎁 เครดิตฟรี: ได้เครดิตฟรีเมื่อลงทะเบียน
ราคา AI ในปี 2026 (ต่อล้าน Token):
- GPT-4.1: $8
- Claude Sonnet 4.5: $15
- Gemini 2.5 Flash: $2.50
- DeepSeek V3.2: $0.42 (ราคาถูกที่สุด!)
ลองนำโค้ดจากบทความนี้ไปประยุกต์ใช้กับ API ของ HolySheep ดูนะครับ รับรองว่าคุ้มค่าแน่นอน!
👉 สมัคร HolySheep AI — รับเครดิตฟรีเมื่อลงทะเบียน