나는이 fetch-api
POST
요청을 :
fetch(url, {
method: 'POST',
body: formData,
credentials: 'include'
})
이에 대한 기본 시간 제한이 무엇인지 알고 싶습니다. 3 초 또는 무한 초와 같은 특정 값으로 어떻게 설정할 수 있습니까?
나는이 fetch-api
POST
요청을 :
fetch(url, {
method: 'POST',
body: formData,
credentials: 'include'
})
이에 대한 기본 시간 제한이 무엇인지 알고 싶습니다. 3 초 또는 무한 초와 같은 특정 값으로 어떻게 설정할 수 있습니까?
답변:
주석에서 지적했듯이 원래 답변의 코드는 약속이 해결 / 거부 된 후에도 타이머를 계속 실행합니다.
아래 코드는이 문제를 해결합니다.
function timeout(ms, promise) {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
reject(new Error('TIMEOUT'))
}, ms)
promise
.then(value => {
clearTimeout(timer)
resolve(value)
})
.catch(reason => {
clearTimeout(timer)
reject(reason)
})
})
}
지정된 기본값이 없습니다. 사양 은 시간 초과에 대해 전혀 논의하지 않습니다.
일반적으로 프라 미스에 대한 자체 시간 초과 래퍼를 구현할 수 있습니다.
// Rough implementation. Untested.
function timeout(ms, promise) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
reject(new Error("timeout"))
}, ms)
promise.then(resolve, reject)
})
}
timeout(1000, fetch('/hello')).then(function(response) {
// process response
}).catch(function(error) {
// might be a timeout error
})
설명한 바와 같이 https://github.com/github/fetch/issues/175 하여 설명 https://github.com/mislav
.reject()
이미 해결 된 약속을 호출 하면 아무 일도 일어나지 않기 때문에 시간 초과가 계속되는 것은 중요 하지 않습니다.
Promise.race를 사용 하는이 요점 의 깔끔한 접근 방식이 정말 마음에 듭니다.
fetchWithTimeout.js
export default function (url, options, timeout = 7000) {
return Promise.race([
fetch(url, options),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('timeout')), timeout)
)
]);
}
main.js
import fetch from './fetchWithTimeout'
// call as usual or with timeout as 3rd argument
fetch('http://google.com', options, 5000) // throw after max 5 seconds timeout error
.then((result) => {
// handle result
})
.catch((e) => {
// handle errors and timeout error
})
fetch
오류가 발생 하면 "처리되지 않은 거부" 가 발생합니다 . 이는 실패 를 처리 ( ) 하고 시간 초과가 아직 발생하지 않은 경우 다시 던짐 으로써 해결할 수 있습니다 . .catch
fetch
약속 경주 솔루션을 사용하면 요청이 중단되고 백그라운드에서 여전히 대역폭을 소비하고 처리중인 동안 허용되는 최대 동시 요청이 낮아집니다.
대신 AbortController 를 사용하여 실제로 요청을 중단하십시오. 다음은 예제입니다.
const controller = new AbortController()
// 5 second timeout:
const timeoutId = setTimeout(() => controller.abort(), 5000)
fetch(url, { signal: controller.signal }).then(response => {
// completed request before timeout fired
// If you only wanted to timeout the request, not the response, add:
// clearTimeout(timeoutId)
})
AbortController는 가져 오기뿐만 아니라 읽기 / 쓰기 가능한 스트림에도 사용할 수 있습니다. 더 많은 새로운 기능 (특히 약속 기반 기능)은이 기능을 점점 더 많이 사용할 것입니다. NodeJS는 또한 AbortController를 스트림 / 파일 시스템에 구현했습니다. 웹 블루투스도 조사 중이라는 것을 알고 있습니다.
Endless의 탁월한 답변을 바탕으로 유용한 유틸리티 기능을 만들었습니다.
const fetchTimeout = (url, ms, { signal, ...options } = {}) => {
const controller = new AbortController();
const promise = fetch(url, { signal: controller.signal, ...options });
if (signal) signal.addEventListener("abort", () => controller.abort());
const timeout = setTimeout(() => controller.abort(), ms);
return promise.finally(() => clearTimeout(timeout));
};
const controller = new AbortController();
document.querySelector("button.cancel").addEventListener("click", () => controller.abort());
fetchTimeout("example.json", 5000, { signal: controller.signal })
.then(response => response.json())
.then(console.log)
.catch(error => {
if (error.name === "AbortError") {
// fetch aborted either due to timeout or due to user clicking the cancel button
} else {
// network error or json parsing error
}
});
도움이 되었기를 바랍니다.
Fetch API에는 아직 시간 초과 지원이 없습니다. 그러나 그것은 약속으로 포장함으로써 달성 될 수 있습니다.
예를 들어.
function fetchWrapper(url, options, timeout) {
return new Promise((resolve, reject) => {
fetch(url, options).then(resolve, reject);
if (timeout) {
const e = new Error("Connection timed out");
setTimeout(reject, timeout, e);
}
});
}
편집 : 가져 오기 요청은 여전히 백그라운드에서 실행 중이며 콘솔에 오류가 기록 될 가능성이 높습니다.
실제로 Promise.race
접근 방식이 더 좋습니다.
참조 Promise.race ()는 이 링크를 참조하십시오.
레이스는 모든 약속이 동시에 실행되고 약속 중 하나가 값을 반환하는 즉시 레이스가 중지됨을 의미합니다. 따라서 하나의 값만 반환 됩니다. 가져 오기 시간이 초과되면 호출 할 함수를 전달할 수도 있습니다.
fetchWithTimeout(url, {
method: 'POST',
body: formData,
credentials: 'include',
}, 5000, () => { /* do stuff here */ });
이것이 귀하의 관심을 끄는 경우 가능한 구현은 다음과 같습니다.
function fetchWithTimeout(url, options, delay, onTimeout) {
const timer = new Promise((resolve) => {
setTimeout(resolve, delay, {
timeout: true,
});
});
return Promise.race([
fetch(url, options),
timer
]).then(response => {
if (response.timeout) {
onTimeout();
}
return response;
});
}
timeoutPromise 래퍼를 만들 수 있습니다.
function timeoutPromise(timeout, err, promise) {
return new Promise(function(resolve,reject) {
promise.then(resolve,reject);
setTimeout(reject.bind(null,err), timeout);
});
}
그런 다음 약속을 래핑 할 수 있습니다.
timeoutPromise(100, new Error('Timed Out!'), fetch(...))
.then(...)
.catch(...)
실제로 기본 연결을 취소하지는 않지만 약속 시간을 초과 할 수 있습니다.
참고
코드에서 시간 제한을 구성하지 않은 경우 브라우저의 기본 요청 시간 제한이됩니다.
1) Firefox-90 초
about:config
Firefox URL 필드에 입력하십시오 . 키에 해당하는 값 찾기network.http.connection-timeout
2) 크롬-300 초
fetchTimeout (url,options,timeout=3000) {
return new Promise( (resolve, reject) => {
fetch(url, options)
.then(resolve,reject)
setTimeout(reject,timeout);
})
}
c-promise2 lib를 사용하면 시간 초과가있는 취소 가능한 가져 오기가 다음과 같을 수 있습니다 ( Live jsfiddle 데모 ).
import CPromise from "c-promise2"; // npm package
function fetchWithTimeout(url, {timeout, ...fetchOptions}= {}) {
return new CPromise((resolve, reject, {signal}) => {
fetch(url, {...fetchOptions, signal}).then(resolve, reject)
}, timeout)
}
const chain = fetchWithTimeout("https://run.mocky.io/v3/753aa609-65ae-4109-8f83-9cfe365290f0?mocky-delay=10s", {timeout: 5000})
.then(request=> console.log('done'));
// chain.cancel(); - to abort the request before the timeout
이 코드는 npm 패키지 cp-fetch