Ðак Ð¼Ñ Ð·Ð½Ð°ÐµÐ¼, меÑод fetch возвÑаÑÐ°ÐµÑ Ð¿ÑомиÑ. Рв JavaScript в Ñелом Ð½ÐµÑ Ð¿Ð¾Ð½ÑÑÐ¸Ñ Â«Ð¾ÑменÑ» пÑомиÑа. Ðак же пÑеÑваÑÑ Ð·Ð°Ð¿ÑÐ¾Ñ fetch?
ÐÐ»Ñ ÑакиÑ
Ñелей ÑÑÑеÑÑвÑÐµÑ ÑпеÑиалÑнÑй вÑÑÑоеннÑй обÑекÑ: AbortController, коÑоÑÑй можно иÑполÑзоваÑÑ Ð´Ð»Ñ Ð¾ÑÐ¼ÐµÐ½Ñ Ð½Ðµ ÑолÑко fetch, но и дÑÑгиÑ
аÑинÑ
ÑоннÑÑ
задаÑ.
ÐÑполÑзоваÑÑ ÐµÐ³Ð¾ доÑÑаÑоÑно пÑоÑÑо:
-
Шаг 1: ÑоздаÑм конÑÑоллеÑ:
let controller = new AbortController();ÐонÑÑоллеÑ
controllerâ ÑÑезвÑÑайно пÑоÑÑой обÑекÑ.- Ðн Ð¸Ð¼ÐµÐµÑ ÐµÐ´Ð¸Ð½ÑÑвеннÑй меÑод
abort()и единÑÑвенное ÑвойÑÑвоsignal. - ÐÑи вÑзове
abort():- генеÑиÑÑеÑÑÑ ÑобÑÑие Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼
abortна обÑекÑеcontroller.signal - ÑвойÑÑво
controller.signal.abortedÑÑановиÑÑÑ ÑавнÑмtrue.
- генеÑиÑÑеÑÑÑ ÑобÑÑие Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼
ÐÑе, кÑо Ñ Ð¾ÑÐµÑ ÑзнаÑÑ Ð¾ вÑзове
abort(), ÑÑавÑÑ Ð¾Ð±ÑабоÑÑики наcontroller.signal, ÑÑÐ¾Ð±Ñ Ð¾ÑÑлеживаÑÑ ÐµÐ³Ð¾.ÐÐ¾Ñ Ñак (пока без
fetch):let controller = new AbortController(); let signal = controller.signal; // ÑÑабаÑÑÐ²Ð°ÐµÑ Ð¿Ñи вÑзове controller.abort() signal.addEventListener('abort', () => alert("оÑмена!")); controller.abort(); // оÑмена! alert(signal.aborted); // true - Ðн Ð¸Ð¼ÐµÐµÑ ÐµÐ´Ð¸Ð½ÑÑвеннÑй меÑод
-
Шаг 2: пеÑедайÑе ÑвойÑÑво
signalопÑией в меÑодfetch:let controller = new AbortController(); fetch(url, { signal: controller.signal });ÐеÑод
fetchÑÐ¼ÐµÐµÑ ÑабоÑаÑÑ ÑAbortController, он ÑлÑÑÐ°ÐµÑ ÑобÑÑиеabortнаsignal. -
Шаг 3: ÑÑÐ¾Ð±Ñ Ð¿ÑеÑваÑÑ Ð²Ñполнение
fetch, вÑзовиÑеcontroller.abort():controller.abort();ÐÐ¾Ñ Ð¸ вÑÑ:
fetchполÑÑÐ°ÐµÑ ÑобÑÑие изsignalи пÑеÑÑÐ²Ð°ÐµÑ Ð·Ð°Ð¿ÑоÑ.
Ðогда fetch оÑменÑеÑÑÑ, его пÑÐ¾Ð¼Ð¸Ñ Ð·Ð°Ð²ÐµÑÑаеÑÑÑ Ñ Ð¾Ñибкой AbortError, поÑÑÐ¾Ð¼Ñ Ð¼Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð¾Ð±ÑабоÑаÑÑ ÐµÑ, напÑимеÑ, в try..catch:
// пÑеÑваÑÑ ÑеÑез 1 ÑекÑндÑ
let controller = new AbortController();
setTimeout(() => controller.abort(), 1000);
try {
let response = await fetch('/article/fetch-abort/demo/hang', {
signal: controller.signal
});
} catch(err) {
if (err.name == 'AbortError') { // обÑабоÑаÑÑ Ð¾ÑÐ¸Ð±ÐºÑ Ð¾Ñ Ð²Ñзова abort()
alert("ÐÑеÑвано!");
} else {
throw err;
}
}
AbortController â маÑÑÑабиÑÑемÑй, он позволÑÐµÑ Ð¾ÑмениÑÑ Ð½ÐµÑколÑко вÑзовов fetch одновÑеменно.
ÐапÑимеÑ, здеÑÑ Ð¼Ñ Ð·Ð°Ð¿ÑаÑиваем много URL паÑаллелÑно, и конÑÑÐ¾Ð»Ð»ÐµÑ Ð¿ÑеÑÑÐ²Ð°ÐµÑ Ð¸Ñ Ð²Ñе:
let urls = [...]; // ÑпиÑок URL Ð´Ð»Ñ Ð¿Ð°ÑаллелÑнÑÑ
fetch
let controller = new AbortController();
let fetchJobs = urls.map(url => fetch(url, {
signal: controller.signal
}));
let results = await Promise.all(fetchJobs);
// еÑли оÑкÑда-Ñо вÑзваÑÑ controller.abort(),
// Ñо ÑÑо пÑеÑвÑÑ Ð²Ñе вÑÐ·Ð¾Ð²Ñ fetch
ÐÑли Ñ Ð½Ð°Ñ ÐµÑÑÑ ÑобÑÑвеннÑе аÑинÑ
ÑоннÑе задаÑи, оÑлиÑнÑе Ð¾Ñ fetch, Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ иÑполÑзоваÑÑ Ð¾Ð´Ð¸Ð½ AbortController Ð´Ð»Ñ Ð¸Ñ
оÑÑановки вмеÑÑе Ñ fetch.
ÐÑжно лиÑÑ ÑлÑÑаÑÑ ÐµÐ³Ð¾ ÑобÑÑие abort:
let urls = [...];
let controller = new AbortController();
let ourJob = new Promise((resolve, reject) => { // наÑа задаÑа
...
controller.signal.addEventListener('abort', reject);
});
let fetchJobs = urls.map(url => fetch(url, { // запÑоÑÑ fetch
signal: controller.signal
}));
// ожидаÑÑ Ð²ÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð½Ð°Ñей задаÑи и вÑеÑ
запÑоÑов
let results = await Promise.all([...fetchJobs, ourJob]);
// вÑзов оÑкÑда-нибÑÐ´Ñ ÐµÑÑ:
// controller.abort() пÑеÑвÑÑ Ð²Ñе вÑÐ·Ð¾Ð²Ñ fetch и наÑи задаÑи
Так ÑÑо AbortController ÑÑÑеÑÑвÑÐµÑ Ð½Ðµ ÑолÑко Ð´Ð»Ñ fetch, ÑÑо ÑнивеÑÑалÑнÑй обÑÐµÐºÑ Ð´Ð»Ñ Ð¾ÑÐ¼ÐµÐ½Ñ Ð°ÑинÑ
ÑоннÑÑ
задаÑ, в fetch вÑÑÑоена инÑегÑаÑÐ¸Ñ Ñ Ð½Ð¸Ð¼.
ÐомменÑаÑии
<code>, Ð´Ð»Ñ Ð½ÐµÑколÑÐºÐ¸Ñ ÑÑÑок кода — Ñег<pre>, еÑли болÑÑе 10 ÑÑÑок — ÑÑÑÐ»ÐºÑ Ð½Ð° пеÑоÑниÑÑ (plnkr, JSBin, codepenâ¦)