Существует новый API для запросов от JavaScript: fetch(). Есть ли встроенный механизм для отмены этих запросов в полете?
Как мне отменить запрос HTTP fetch()?
Ответ 1
TL/DR:
fetch
теперь поддерживает параметр signal
состоянию на 20 сентября 2017 года, но, похоже, не все браузеры поддерживают этот atm.
Это изменение мы увидим очень скоро, и поэтому вы сможете отменить запрос, используя AbortController
AbortSignal
.
Длинная версия
Как:
Вот как это работает:
Шаг 1: Вы создаете AbortController
(сейчас я только что использовал это)
const controller = new AbortController()
Шаг 2: Вы получаете сигнал AbortController
подобный этому:
const signal = controller.signal
Шаг 3: Вы передаете signal
для извлечения следующим образом:
fetch(urlToFetch, {
method: 'get',
signal: signal, // <------ This is our AbortSignal
})
Шаг 4: Просто прерывайте всякий раз, когда вам нужно:
controller.abort();
Вот пример того, как это будет работать (работает в Firefox 57+):
<script>
// Create an instance.
const controller = new AbortController()
const signal = controller.signal
/*
// Register a listenr.
signal.addEventListener("abort", () => {
console.log("aborted!")
})
*/
function beginFetching() {
console.log('Now fetching');
var urlToFetch = "https://httpbin.org/delay/3";
fetch(urlToFetch, {
method: 'get',
signal: signal,
})
.then(function(response) {
console.log('Fetch complete. (Not aborted)');
}).catch(function(err) {
console.error(' Err: ${err}');
});
}
function abortFetching() {
console.log('Now aborting');
// Abort.
controller.abort()
}
</script>
<h1>Example of fetch abort</h1>
<hr>
<button onclick="beginFetching();">
Begin
</button>
<button onclick="abortFetching();">
Abort
</button>
Ответ 2
Я не верю, что есть способ отменить запрос с существующим API-интерфейсом. Продолжается обсуждение этого вопроса на https://github.com/whatwg/fetch/issues/27
Обновление до 2017 года: разрешение по-прежнему отсутствует. Запросы не могут быть отменены. Больше обсуждений на https://github.com/whatwg/fetch/issues/447
Ответ 3
https://developers.google.com/web/updates/2017/09/abortable-fetch
настроить:
const controller = new AbortController();
const signal = controller.signal;
fetch(url, { signal }).then(response => {
return response.text();
}).then(text => {
console.log(text);
});
прервать: controller.abort()
работает в версии 16 (2017-10-17), Firefox 57 (2017-11-14), настольное Safari 11.1 (2018-03-29), IOS Safari 11.4 (2018-03-29), Chrome 67 (2018-05 -29) и позже.
Ответ 4
По состоянию на февраль 2018 года fetch()
можно отменить с помощью приведенного ниже кода в Chrome (см. " Использование читаемых потоков", чтобы включить поддержку Firefox). Для catch()
не AbortController
никакой ошибки, и это временное решение, пока AbortController
будет полностью принят.
fetch('YOUR_CUSTOM_URL')
.then(response => {
if (!response.body) {
console.warn("ReadableStream is not yet supported in this browser. See https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream")
return response;
}
// get reference to ReadableStream so we can cancel/abort this fetch request.
const responseReader = response.body.getReader();
startAbortSimulation(responseReader);
// Return a new Response object that implements a custom reader.
return new Response(new ReadableStream(new ReadableStreamConfig(responseReader)));
})
.then(response => response.blob())
.then(data => console.log('Download ended. Bytes downloaded:', data.size))
.catch(error => console.error('Error during fetch()', error))
// Here an example of how to abort request once fetch() starts
function startAbortSimulation(responseReader) {
// abort fetch() after 50ms
setTimeout(function() {
console.log('aborting fetch()...');
responseReader.cancel()
.then(function() {
console.log('fetch() aborted');
})
},50)
}
// ReadableStream constructor requires custom implementation of start() method
function ReadableStreamConfig(reader) {
return {
start(controller) {
read();
function read() {
reader.read().then(({done,value}) => {
if (done) {
controller.close();
return;
}
controller.enqueue(value);
read();
})
}
}
}
}
Ответ 5
Пока нет правильного решения, как говорит @spro.
Однако, если у вас есть ответ в полете и вы используете ReadableStream, вы можете закрыть поток, чтобы отменить запрос.
fetch('http://example.com').then((res) => {
const reader = res.body.getReader();
/*
* Your code for reading streams goes here
*/
// To abort/cancel HTTP request...
reader.cancel();
});