μ΅μ μΉ κ°λ°μμ ν¨κ³Όμ μΈ μμ² μ·¨μλ₯Ό μν JavaScriptμ AbortController μ¬μ©λ²μ λν μ’ ν© κ°μ΄λμ λλ€. μ€μ©μ μΈ ν¨ν΄κ³Ό λͺ¨λ² μ¬λ‘λ₯Ό λ°°μ보μΈμ.
JavaScript AbortController: μμ² μ·¨μ ν¨ν΄ λ§μ€ν°νκΈ°
μ΅μ μΉ κ°λ°μμ λΉλκΈ° μμ
μ νν μΌμ
λλ€. μ격 μλ²μμ λ°μ΄ν°λ₯Ό κ°μ Έμ€κ±°λ, νμΌμ μ
λ‘λνκ±°λ, λ°±κ·ΈλΌμ΄λμμ 볡μ‘ν κ³μ°μ μννλ λ±, JavaScriptλ νλ‘λ―Έμ€μ λΉλκΈ° ν¨μμ ν¬κ² μμ‘΄ν©λλ€. νμ§λ§ μ μ΄λμ§ μλ λΉλκΈ° μμ
μ μ±λ₯ λ¬Έμ , 리μμ€ λλΉ, μκΈ°μΉ μμ λμμΌλ‘ μ΄μ΄μ§ μ μμ΅λλ€. λ°λ‘ μ΄λ΄ λ AbortController
κ° μ μ©ν©λλ€. μ΄ κΈμ JavaScriptμ AbortController
λ₯Ό μ¬μ©νμ¬ μμ² μ·¨μ ν¨ν΄μ λ§μ€ν°νλ μ’
ν© κ°μ΄λλ₯Ό μ 곡νμ¬, κΈλ‘λ² μ¬μ©μλ₯Ό μν λ κ²¬κ³ νκ³ ν¨μ¨μ μΈ μΉ μ ν리μΌμ΄μ
μ ꡬμΆν μ μλλ‘ λμ΅λλ€.
AbortControllerλ 무μμΈκ°?
AbortController
λ νλ μ΄μμ μΉ μμ²μ μ€λ¨ν μ μκ² ν΄μ£Όλ λ΄μ₯ JavaScript APIμ
λλ€. μμ
μ΄ μ·¨μλμ΄μΌ ν¨μ μ리λ μ νΈλ₯Ό λ³΄λ΄ λΆνμν λ€νΈμν¬ νΈλν½κ³Ό 리μμ€ μλΉλ₯Ό λ°©μ§νλ λ°©λ²μ μ 곡ν©λλ€. AbortController
λ μ·¨μλ λΉλκΈ° μμ
μ μ λ¬λλ AbortSignal
κ³Ό ν¨κ» μλν©λλ€. μ΄ λμ ν¨κ» λΉλκΈ° μμ
μ κ΄λ¦¬νκΈ° μν κ°λ ₯νκ³ μ μ°ν λ©μ»€λμ¦μ μ 곡ν©λλ€.
AbortControllerλ₯Ό μ¬μ©νλ μ΄μ
AbortController
λ₯Ό μ¬μ©νλ©΄ μ¬λ¬ μλ리μ€μμ μ΄μ μ μ»μ μ μμ΅λλ€:
- μ±λ₯ ν₯μ: λ μ΄μ νμ μλ μ§ν μ€μΈ μμ²μ μ·¨μνλ©΄ λ€νΈμν¬ νΈλν½μ΄ μ€μ΄λ€κ³ 리μμ€κ° ν보λμ΄ λ λΉ λ₯΄κ³ λ°μμ±μ΄ μ’μ μ ν리μΌμ΄μ μ λ§λ€ μ μμ΅λλ€.
- κ²½μ μν λ°©μ§: μ¬λ¬ μμ²μ΄ λΉ λ₯΄κ² μ°μμ μΌλ‘ μμλ λ, κ°μ₯ μ΅κ·Ό μμ²μ κ²°κ³Όλ§μ΄ μλ―Έ μμ μ μμ΅λλ€. μ΄μ μμ²μ μ·¨μνλ©΄ κ²½μ μνλ₯Ό λ°©μ§νκ³ λ°μ΄ν° μΌκ΄μ±μ 보μ₯ν©λλ€.
- μ¬μ©μ κ²½ν κ°μ : 'μ λ ₯ μ κ²μ'μ΄λ λμ μ½ν μΈ λ‘λ©κ³Ό κ°μ μλ리μ€μμ μ€λλ μμ²μ μ·¨μνλ©΄ λ λΆλλ½κ³ λ°μμ± μλ μ¬μ©μ κ²½νμ μ 곡ν©λλ€.
- 리μμ€ κ΄λ¦¬: λͺ¨λ°μΌ κΈ°κΈ° λ° λ¦¬μμ€κ° μ νλ νκ²½μμλ μ€λ μ€νλκ±°λ λΆνμν μμ²μ μ·¨μνμ¬ λ°°ν°λ¦¬ μλͺ κ³Ό λμνμ μ μ½νλ λ° λμμ΄ λ©λλ€.
κΈ°λ³Έ μ¬μ©λ²
λ€μμ fetch
APIμ ν¨κ» AbortController
λ₯Ό μ¬μ©νλ λ°©λ²μ 보μ¬μ£Όλ κΈ°λ³Έ μμ μ
λλ€:
μμ 1: κ°λ¨ν Fetch μ·¨μ
const controller = new AbortController();
const signal = controller.signal;
fetch('https://api.example.com/data', { signal })
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(data => {
console.log(data);
})
.catch(error => {
if (error.name === 'AbortError') {
console.log('Fetch aborted');
} else {
console.error('Fetch error:', error);
}
});
// Abort the fetch request after 5 seconds
setTimeout(() => {
controller.abort();
}, 5000);
μ€λͺ :
- μλ‘μ΄
AbortController
κ° μμ±λ©λλ€. AbortController
μsignal
μμ±μ΄fetch
μ΅μ μ μ λ¬λ©λλ€.setTimeout
ν¨μλ 5μ΄ νμcontroller.abort()
λ₯Ό νΈμΆνμ¬ μμ²μ μ€λ¨νλ λ° μ¬μ©λ©λλ€.catch
λΈλ‘μ μμ²μ΄ μ€λ¨λ λ λ°μνλAbortError
λ₯Ό μ²λ¦¬ν©λλ€.
κ³ κΈ μ·¨μ ν¨ν΄
κΈ°λ³Έ μμ μΈμλ AbortController
λ₯Ό ν¨κ³Όμ μΌλ‘ νμ©ν μ μλ λͺ κ°μ§ κ³ κΈ ν¨ν΄μ΄ μμ΅λλ€.
ν¨ν΄ 1: μ»΄ν¬λνΈ μΈλ§μ΄νΈ μ μ·¨μ (React μμ )
Reactμ κ°μ μ»΄ν¬λνΈ κΈ°λ° νλ μμν¬μμλ μ»΄ν¬λνΈκ° λ§μ΄νΈλ λ μμ²μ μμνκ³ μ»΄ν¬λνΈκ° μΈλ§μ΄νΈλ λ μ·¨μνλ κ²μ΄ μΌλ°μ μ λλ€. μ΄λ λ©λͺ¨λ¦¬ λμλ₯Ό λ°©μ§νκ³ μ ν리μΌμ΄μ μ΄ λ μ΄μ 보μ΄μ§ μλ μ»΄ν¬λνΈμ λ°μ΄ν°λ₯Ό κ³μ μ²λ¦¬νμ§ μλλ‘ λ³΄μ₯ν©λλ€.
import React, { useState, useEffect } from 'react';
function DataComponent() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const controller = new AbortController();
const signal = controller.signal;
const fetchData = async () => {
try {
const response = await fetch('https://api.example.com/data', { signal });
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const json = await response.json();
setData(json);
} catch (error) {
if (error.name === 'AbortError') {
console.log('Fetch aborted');
} else {
setError(error);
}
} finally {
setLoading(false);
}
};
fetchData();
return () => {
controller.abort(); // Cleanup function to abort the request
};
}, []); // Empty dependency array ensures this runs only on mount/unmount
if (loading) return Loading...
;
if (error) return Error: {error.message}
;
return (
Data:
{JSON.stringify(data, null, 2)}
);
}
export default DataComponent;
μ€λͺ :
useEffect
ν μ μ»΄ν¬λνΈκ° λ§μ΄νΈλ λ λΆμ ν¨κ³Ό(μ΄ κ²½μ° λ°μ΄ν° κ°μ Έμ€κΈ°)λ₯Ό μννλ λ° μ¬μ©λ©λλ€.AbortController
λuseEffect
ν λ΄μμ μμ±λ©λλ€.useEffect
κ° λ°ννλ μ 리 ν¨μλ μ»΄ν¬λνΈκ° μΈλ§μ΄νΈλ λcontroller.abort()
λ₯Ό νΈμΆνμ¬ μ§ν μ€μΈ μμ²μ΄ μ·¨μλλλ‘ λ³΄μ₯ν©λλ€.- λΉ μμ‘΄μ± λ°°μ΄(
[]
)μ΄useEffect
μ μ λ¬λμ΄ μ΄ ν¨κ³Όκ° λ§μ΄νΈ μ ν λ², μΈλ§μ΄νΈ μ ν λ²λ§ μ€νλλλ‘ ν©λλ€.
ν¨ν΄ 2: λλ°μ΄μ±κ³Ό μ€λ‘νλ§
λλ°μ΄μ±κ³Ό μ€λ‘νλ§μ ν¨μκ° μ€νλλ λΉλλ₯Ό μ ννλ λ° μ¬μ©λλ κΈ°μ μ
λλ€. 'μ
λ ₯ μ κ²μ'μ΄λ μ°½ ν¬κΈ° μ‘°μ κ³Ό κ°μ΄ λΉλ²ν μ΄λ²€νΈκ° λΉμ©μ΄ λ§μ΄ λλ μμ
μ νΈλ¦¬κ±°ν μ μλ μλ리μ€μμ νν μ¬μ©λ©λλ€. AbortController
λ λλ°μ΄μ± λ° μ€λ‘νλ§κ³Ό ν¨κ» μ¬μ©νμ¬ μ μ΄λ²€νΈκ° λ°μν λ μ΄μ μμ²μ μ·¨μν μ μμ΅λλ€.
μμ : AbortControllerλ₯Ό μ¬μ©ν λλ°μ΄μ€ κ²μ
function debouncedSearch(query, delay = 300) {
let controller = null; // Keep the controller in the scope
return function() {
if (controller) {
controller.abort(); // Abort previous request
}
controller = new AbortController(); // Create a new AbortController
const signal = controller.signal;
return new Promise((resolve, reject) => {
setTimeout(() => {
fetch(`https://api.example.com/search?q=${query}`, { signal })
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(data => {
resolve(data);
})
.catch(error => {
if (error.name === 'AbortError') {
console.log('Search Aborted for: ' + query);
} else {
reject(error);
}
});
}, delay);
});
};
}
// Usage Example:
const search = debouncedSearch('Example Query');
search().then(results => console.log(results)).catch(error => console.error(error)); //Initial search
search().then(results => console.log(results)).catch(error => console.error(error)); //Another search; aborts the previous
search().then(results => console.log(results)).catch(error => console.error(error)); //...and another
μ€λͺ :
debouncedSearch
ν¨μλ κ²μ ν¨μμ λλ°μ΄μ€λ λ²μ μ λ°νν©λλ€.- λλ°μ΄μ€λ ν¨μκ° νΈμΆλ λλ§λ€ λ¨Όμ
controller.abort()
λ₯Ό μ¬μ©νμ¬ μ΄μ μμ²μ μ€λ¨ν©λλ€. - κ·Έλ° λ€μ μλ‘μ΄
AbortController
κ° μμ±λμ΄ μ μμ²μ μμνλ λ° μ¬μ©λ©λλ€. setTimeout
ν¨μλ μμ²μ΄ μ΄λ£¨μ΄μ§κΈ° μ μ μ§μ°μ λμ νμ¬ μ¬μ©μκ° μΌμ μκ° λμ νμ΄νμ λ©μΆ νμλ§ κ²μμ΄ μνλλλ‘ ν©λλ€.
ν¨ν΄ 3: μ¬λ¬ AbortSignal κ²°ν©νκΈ°
κ²½μ°μ λ°λΌ μ¬λ¬ 쑰건μ λ°λΌ μμ²μ μ€λ¨ν΄μΌ ν μλ μμ΅λλ€. μλ₯Ό λ€μ΄, νμμμμ΄ λ°μνκ±°λ μ¬μ©μκ° νμ΄μ§μμ λ²μ΄λ κ²½μ° μμ²μ μ€λ¨νκ³ μΆμ μ μμ΅λλ€. μ¬λ¬ AbortSignal
μΈμ€ν΄μ€λ₯Ό λ¨μΌ μ νΈλ‘ κ²°ν©νμ¬ μ΄λ₯Ό λ¬μ±ν μ μμ΅λλ€.
μ΄ ν¨ν΄μ κΈ°λ³Έμ μΌλ‘ μ§μ μ§μλμ§ μμΌλ©°, μΌλ°μ μΌλ‘ μ체 κ²°ν© λ‘μ§μ ꡬνν΄μΌ ν©λλ€.
ν¨ν΄ 4: νμμμ λ° λ°λλΌμΈ
μμ²μ λν νμμμ μ€μ μ μμ²μ΄ 무기ν μ€λ¨λλ κ²μ λ°©μ§νλ λ° μ€μν©λλ€. AbortController
λ₯Ό μ¬μ©νλ©΄ νμμμμ μ½κ² ꡬνν μ μμ΅λλ€.
async function fetchDataWithTimeout(url, timeout) {
const controller = new AbortController();
const signal = controller.signal;
const timeoutId = setTimeout(() => {
controller.abort();
}, timeout);
try {
const response = await fetch(url, { signal });
clearTimeout(timeoutId); // Clear timeout if request completes successfully
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
clearTimeout(timeoutId); // Clear timeout in case of any error
throw error;
}
}
// Usage:
fetchDataWithTimeout('https://api.example.com/data', 3000) // 3 seconds timeout
.then(data => console.log(data))
.catch(error => console.error(error));
μ€λͺ :
fetchDataWithTimeout
ν¨μλ URLκ³Ό νμμμ κ°μ μΈμλ‘ λ°μ΅λλ€.setTimeout
ν¨μλ μ§μ λ νμμμ νμ μμ²μ μ€λ¨νλ λ° μ¬μ©λ©λλ€.clearTimeout
ν¨μλ μμ²μ΄ μ±κ³΅μ μΌλ‘ μλ£λκ±°λ μ€λ₯κ° λ°μν κ²½μ° νμμμμ΄ ν΄μ λλλ‘try
μcatch
λΈλ‘ λͺ¨λμμ νΈμΆλ©λλ€.
μ μμ κ³ λ €μ¬ν λ° λͺ¨λ² μ¬λ‘
μ μ 컨ν
μ€νΈμμ AbortController
λ‘ μμ
ν λλ λ€μ μ¬νμ κ³ λ €νλ κ²μ΄ μ€μν©λλ€:
- μ§μν: μμ² μ·¨μμ κ΄λ ¨λ μ€λ₯ λ©μμ§ λ° μ¬μ©μ μΈν°νμ΄μ€ μμλ λ€λ₯Έ μ§μμ μ¬μ©μκ° μ κ·Όν μ μλλ‘ μ§μνλμ΄μΌ ν©λλ€.
- λ€νΈμν¬ μν: λ€νΈμν¬ μνλ μ§λ¦¬μ μμΉμ λ°λΌ ν¬κ² λ€λ₯Ό μ μμ΅λλ€. λ€λ₯Έ μ§μμ μμ λ€νΈμν¬ μ§μ° μκ° λ° λμνμ λ°λΌ νμμμ κ°κ³Ό μ·¨μ μ λ΅μ μ‘°μ ν΄μΌ ν©λλ€.
- μλ² μΈ‘ κ³ λ €μ¬ν: μλ² μΈ‘ API μλν¬μΈνΈκ° μ·¨μλ μμ²μ μ μμ μΌλ‘ μ²λ¦¬νλμ§ νμΈν΄μΌ ν©λλ€. μλ₯Ό λ€μ΄, ν΄λΌμ΄μΈνΈκ° μμ²μ μ€λ¨ν κ²½μ° μμ² μ²λ¦¬λ₯Ό μ€μ§νλ λ©μ»€λμ¦μ ꡬνν μ μμ΅λλ€.
- μ κ·Όμ±: μμ²μ΄ μ·¨μλμμ λ μ¬μ©μμκ² λͺ ννκ³ μ μ΅ν νΌλλ°±μ μ 곡ν΄μΌ ν©λλ€. μ΄λ μ¬μ©μκ° μμ²μ΄ μ·¨μλ μ΄μ λ₯Ό μ΄ν΄νκ³ μ μ ν μ‘°μΉλ₯Ό μ·¨νλ λ° λμμ΄ λ μ μμ΅λλ€.
- λͺ¨λ°μΌ vs. λ°μ€ν¬ν±: λͺ¨λ°μΌ μ¬μ©μλ μ°κ²°μ΄ λ λΆμμ ν μ μμΌλ―λ‘, λͺ¨λ°μΌ κΈ°κΈ°μ λν νμμμ λ° μ€λ₯ μ²λ¦¬κ° κ²¬κ³ νμ§ νμΈν΄μΌ ν©λλ€.
- λ€μν λΈλΌμ°μ : AbortController APIμ κ΄λ ¨νμ¬ νΈνμ± λ¬Έμ κ° μλμ§ νμΈνκΈ° μν΄ μ¬λ¬ λΈλΌμ°μ λ° λ²μ μμ ν μ€νΈνλ κ²μ κ³ λ €ν΄μΌ ν©λλ€.
μ€λ₯ μ²λ¦¬
AbortController
λ₯Ό μ¬μ©ν λλ μ μ ν μ€λ₯ μ²λ¦¬κ° μ€μν©λλ€. νμ AbortError
λ₯Ό νμΈνκ³ μ μ νκ² μ²λ¦¬ν΄μΌ ν©λλ€.
try {
// ... fetch code ...
} catch (error) {
if (error.name === 'AbortError') {
console.log('Request was aborted');
// Perform any necessary cleanup or UI updates
} else {
console.error('An error occurred:', error);
// Handle other errors
}
}
κ²°λ‘
JavaScript AbortController
λ λΉλκΈ° μμ
μ κ΄λ¦¬νκ³ μΉ μ ν리μΌμ΄μ
μ μ±λ₯κ³Ό λ°μμ±μ ν₯μμν€λ κ°λ ₯ν λꡬμ
λλ€. κΈ°λ³Έ μ¬μ©λ²κ³Ό κ³ κΈ ν¨ν΄μ μ΄ν΄ν¨μΌλ‘μ¨, κΈλ‘λ² μ¬μ©μμκ² λ λμ μ¬μ©μ κ²½νμ μ 곡νλ λ κ²¬κ³ νκ³ ν¨μ¨μ μΈ μ ν리μΌμ΄μ
μ ꡬμΆν μ μμ΅λλ€. μ ν리μΌμ΄μ
μ μμ² μ·¨μλ₯Ό ꡬνν λ μ§μν, λ€νΈμν¬ μν λ° μλ² μΈ‘ κ³ λ €μ¬νμ κΈ°μ΅νμμμ€.
μμ μ€λͺ λ ν¨ν΄μ νμ©ν¨μΌλ‘μ¨ κ°λ°μλ μμ μκ² λΉλκΈ° μμ μ κ΄λ¦¬νκ³ , 리μμ€ νμ©μ μ΅μ ννλ©°, λ€μν νκ²½κ³Ό κΈλ‘λ² μ¬μ©μμκ² λ°μ΄λ μ¬μ©μ κ²½νμ μ 곡ν μ μμ΅λλ€.
μ΄ μ’
ν© κ°μ΄λκ° JavaScriptμ AbortController
λ₯Ό μ¬μ©νμ¬ μμ² μ·¨μ ν¨ν΄μ λ§μ€ν°νλ λ° κ²¬κ³ ν κΈ°λ°μ μ 곡νκΈ°λ₯Ό λ°λλλ€. μ¦κ±°μ΄ μ½λ© λμΈμ!