JavaScript에서 요청을 작성하기위한 새로운 API 인 fetch ()가 있습니다. 기내에서 이러한 요청을 취소 할 수있는 메커니즘이 있습니까?
답변
TL / DR :
fetch
signal
2017 년 9 월 20 일 현재 매개 변수를 지원 하지만 현재 모든 브라우저에서이 기능을 지원하는 것은 아닙니다 .
2020 업데이트 : 대부분의 주요 브라우저 (Edge, Firefox, Chrome, Safari, Opera 및 기타 몇 가지) 는이 기능을 지원하며 이는 DOM 생활 표준의 일부가되었습니다 . (2020 년 3 월 5 일 현재)
이것은 곧 변경 될 예정이므로 AbortController
s 를 사용하여 요청을 취소 할 수 있습니다 AbortSignal
.
긴 버전
어떻게:
작동 방식은 다음과 같습니다.
1 단계 : 당신은 AbortController
(지금은 방금 이것을 사용 했습니다 )
const controller = new AbortController()
2 단계 : 다음 AbortController
과 같이 s 신호를 얻습니다 .
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>
출처 :
- AbortController 의 최종 버전이 DOM 사양에 추가되었습니다
- 해당 PR 페치 사양 지금 병합됩니다.
- AbortController의 구현을 추적하는 브라우저 버그는 Firefox : # 1378342 , Chromium : # 750599 , WebKit : # 174980 , Edge : # 13009916에서 확인할 수 있습니다.
답변
https://developers.google.com/web/updates/2017/09/abortable-fetch
https://dom.spec.whatwg.org/#aborting-ongoing-activities
// setup AbortController
const controller = new AbortController();
// signal to pass to fetch
const signal = controller.signal;
// fetch as usual
fetch(url, { signal }).then(response => {
...
}).catch(e => {
// catch the abort if you like
if (e.name === 'AbortError') {
...
}
});
// when you want to abort
controller.abort();
엣지 16 (2017-10-17), 파이어 폭스 57 (2017-11-14), 데스크톱 사파리 11.1 (2018-03-29), iOS 사파리 11.4 (2018-03-29), 크롬 67 (2018-05 -29) 이상.
구형 브라우저에서는 github의 whatwg-fetch polyfill 및 AbortController polyfill을 사용할 수 있습니다 . 오래된 브라우저 를 감지하고 폴리 필을 조건부로 사용할 수도 있습니다.
import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only'
import {fetch} from 'whatwg-fetch'
// use native browser implementation if it supports aborting
const abortableFetch = ('signal' in new Request('')) ? window.fetch : fetch
답변
2018 년 2 월 현재 fetch()
Chrome에서 아래 코드를 사용하여 취소 할 수 있습니다 ( Firefox 지원을 사용하려면 Readable Streams 사용 참조). 오류가 발생하지 않으며 완전히 채택 catch()
될 때까지 임시 해결책 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's 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();
})
}
}
}
}
답변
@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();
});
답변
폴리 필하자 :
if(!AbortController){
class AbortController {
constructor() {
this.aborted = false;
this.signal = this.signal.bind(this);
}
signal(abortFn, scope) {
if (this.aborted) {
abortFn.apply(scope, { name: 'AbortError' });
this.aborted = false;
} else {
this.abortFn = abortFn.bind(scope);
}
}
abort() {
if (this.abortFn) {
this.abortFn({ reason: 'canceled' });
this.aborted = false;
} else {
this.aborted = true;
}
}
}
const originalFetch = window.fetch;
const customFetch = (url, options) => {
const { signal } = options || {};
return new Promise((resolve, reject) => {
if (signal) {
signal(reject, this);
}
originalFetch(url, options)
.then(resolve)
.catch(reject);
});
};
window.fetch = customFetch;
}
코드는 테스트되지 않았다는 것을 명심하십시오! 테스트 한 결과 작동하지 않는 경우 알려주십시오. JavaScript 공식 라이브러리에서 ‘fetch’함수를 덮어 쓰려고한다는 경고가 표시 될 수 있습니다.