ææ°ãŠã§ãéçºã«ããã广çãªãªã¯ãšã¹ããã£ã³ã»ã«ã®ããã®JavaScript AbortControllerã®ç·åã¬ã€ããå®è·µçãªãã¿ãŒã³ãšãã¹ããã©ã¯ãã£ã¹ã解説ããŸãã
JavaScript AbortController: ãªã¯ãšã¹ããã£ã³ã»ã«ãã¿ãŒã³ããã¹ã¿ãŒãã
çŸä»£ã®ãŠã§ãéçºã«ãããŠãéåææäœã¯åœããåã®ããã«è¡ãããŠããŸãããªã¢ãŒããµãŒããŒããã®ããŒã¿ååŸããã¡ã€ã«ã®ã¢ããããŒããããã¯ã°ã©ãŠã³ãã§ã®è€éãªèšç®ãªã©ãJavaScriptã¯Promiseãéåæé¢æ°ã«å€§ããäŸåããŠããŸããããããå¶åŸ¡ãããŠããªãéåææäœã¯ãããã©ãŒãã³ã¹ã®åé¡ããªãœãŒã¹ã®ç¡é§é£ããäºæãã¬åäœã«ã€ãªããå¯èœæ§ããããŸããããã§åœ¹ç«ã€ã®ãAbortController
ã§ãããã®èšäºã§ã¯ãJavaScriptã®AbortController
ã䜿çšããŠãªã¯ãšã¹ããã£ã³ã»ã«ãã¿ãŒã³ããã¹ã¿ãŒããããã®å
æ¬çãªã¬ã€ããæäŸããã°ããŒãã«ãªèŠèŽè
åãã«ãããå
ç¢ã§å¹ççãªãŠã§ãã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ã§ããããã«ããŸãã
AbortControllerãšã¯äœãïŒ
AbortController
ã¯ã1ã€ä»¥äžã®ãŠã§ããªã¯ãšã¹ããäžæ¢ïŒabortïŒã§ããJavaScriptã®çµã¿èŸŒã¿APIã§ããæäœããã£ã³ã»ã«ãã¹ãã§ããããšãç¥ãããææ®µãæäŸããäžèŠãªãããã¯ãŒã¯ãã©ãã£ãã¯ããªãœãŒã¹æ¶è²»ãé²ããŸããAbortController
ã¯ããã£ã³ã»ã«å¯Ÿè±¡ã®éåææäœã«æž¡ãããAbortSignal
ãšé£æºããŠåäœããŸããããããäžäœãšãªã£ãŠãéåæã¿ã¹ã¯ã管çããããã®åŒ·åã§æè»ãªã¡ã«ããºã ãæäŸããŸãã
ãªãAbortControllerã䜿çšããã®ãïŒ
AbortController
ã䜿çšããããšã§ã¡ãªãããåŸãããã·ããªãªã¯ããã€ããããŸãïŒ
- ããã©ãŒãã³ã¹ã®åäžïŒ äžèŠã«ãªã£ãé²è¡äžã®ãªã¯ãšã¹ãããã£ã³ã»ã«ããããšã§ããããã¯ãŒã¯ãã©ãã£ãã¯ãåæžããããªãœãŒã¹ãè§£æŸããããããããé«éã§å¿çæ§ã®é«ãã¢ããªã±ãŒã·ã§ã³ã«ã€ãªãããŸãã
- ç«¶åç¶æ ã®é²æ¢ïŒ è€æ°ã®ãªã¯ãšã¹ããç«ãŠç¶ãã«éå§ãããå Žåãææ°ã®ãªã¯ãšã¹ãã®çµæã®ã¿ãéèŠã«ãªãããšããããŸãã以åã®ãªã¯ãšã¹ãããã£ã³ã»ã«ããããšã§ãç«¶åç¶æ ãé²ããããŒã¿ã®äžè²«æ§ã確ä¿ããŸãã
- ãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ã®åäžïŒ å ¥åäžã®æ€çŽ¢ïŒsearch as you typeïŒãåçãªã³ã³ãã³ãã®èªã¿èŸŒã¿ãªã©ã®ã·ããªãªã§ã¯ãå€ããªã¯ãšã¹ãããã£ã³ã»ã«ããããšã§ãããã¹ã ãŒãºã§å¿çæ§ã®é«ããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãæäŸããŸãã
- ãªãœãŒã¹ç®¡çïŒ ã¢ãã€ã«ããã€ã¹ããªãœãŒã¹ã«å¶çŽã®ããç°å¢ã§ã¯ãé·æéå®è¡ããããªã¯ãšã¹ããäžèŠãªãªã¯ãšã¹ãããã£ã³ã»ã«ããããšã§ãããããªãŒå¯¿åœã垯åå¹ ãç¯çŽã§ããŸãã
åºæ¬çãªäœ¿ãæ¹
以äžã¯ãAbortController
ãfetch
APIãšãšãã«äœ¿çšããåºæ¬çãªäŸã§ãïŒ
äŸ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
ã«æž¡ããããšãã§ã¯ããããŠã³ãæã«1åãã¢ã³ããŠã³ãæã«1åã ãå®è¡ãããããšã瀺ããŸãã
ãã¿ãŒã³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
ã€ã³ã¹ã¿ã³ã¹ã1ã€ã®ã·ã°ãã«ã«çµã¿åãããããšã§å®çŸã§ããŸãã
ãã®ãã¿ãŒã³ã¯ãã€ãã£ãã§ã¯çŽæ¥ãµããŒããããŠããããéåžžã¯ç¬èªã®çµã¿åããããžãã¯ãå®è£ ããå¿ èŠããããŸãã
ãã¿ãŒã³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ãšã³ããã€ã³ããããã£ã³ã»ã«ããããªã¯ãšã¹ããé©åã«åŠçããããšã確èªããŠãã ãããããšãã°ãã¯ã©ã€ã¢ã³ãããªã¯ãšã¹ããäžæ¢ããå Žåã«åŠçã忢ããã¡ã«ããºã ãå®è£ ãããšããã§ãããã
- ã¢ã¯ã»ã·ããªãã£ïŒ ãªã¯ãšã¹ãããã£ã³ã»ã«ãããéã«ã¯ããŠãŒã¶ãŒã«æç¢ºã§æçãªãã£ãŒãããã¯ãæäŸããŠãã ãããããã«ããããŠãŒã¶ãŒã¯ãªã¯ãšã¹ãããã£ã³ã»ã«ãããçç±ãçè§£ããé©åãªè¡åããšãããšãã§ããŸãã
- ã¢ãã€ã«å¯Ÿãã¹ã¯ãããïŒ ã¢ãã€ã«ãŠãŒã¶ãŒã¯æ¥ç¶ãäžå®å®ãªå Žåãå€ããããã¿ã€ã ã¢ãŠãããšã©ãŒãã³ããªã³ã°ãã¢ãã€ã«ããã€ã¹åãã«å ç¢ã«ããŠãã ããã
- ç°ãªããã©ãŠã¶ïŒ 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
ã䜿çšãããªã¯ãšã¹ããã£ã³ã»ã«ãã¿ãŒã³ã®ç¿åŸã«åãã確åºããåºç€ãšãªãããšãé¡ã£ãŠããŸããããããŒã³ãŒãã£ã³ã°ïŒ