Mam fetch-api
POST
prośbę:
fetch(url, {
method: 'POST',
body: formData,
credentials: 'include'
})
Chcę wiedzieć, jaki jest domyślny limit czasu w tym przypadku? i jak możemy ustawić ją na określoną wartość, taką jak 3 sekundy lub nieokreślone sekundy?
javascript
ajax
fetch-api
Akshay Lokur
źródło
źródło
.reject()
się do już rozwiązanej obietnicy nic nie daje.Bardzo podoba mi się czyste podejście od tego GIST wykorzystaniem 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 })
źródło
fetch
błąd . Można to rozwiązać poprzez obsługę ( ) błędu i ponowne zgłoszenie, jeśli limit czasu jeszcze nie nastąpił..catch
fetch
Użycie rozwiązania Promise Race spowoduje zawieszenie żądania i nadal zużywa przepustowość w tle oraz obniża maksymalne dozwolone współbieżne żądanie, które jest nadal w trakcie przetwarzania.
Zamiast tego użyj AbortController, aby faktycznie przerwać żądanie. Oto przykład
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 może być również używany do innych rzeczy, nie tylko do pobierania, ale także do odczytywalnych / zapisywalnych strumieni. Nowsze funkcje (szczególnie te oparte na obietnicach) będą z tego coraz częściej korzystać. NodeJS również zaimplementował AbortController w swoich strumieniach / systemie plików. Wiem, że przeglądają to również bluetooth sieciowy
źródło
Opierając się na doskonałej odpowiedzi Endless , stworzyłem przydatną funkcję użytkową.
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 } });
Mam nadzieję, że to pomoże.
źródło
nie ma jeszcze obsługi limitu czasu w interfejsie API pobierania. Ale można to osiągnąć, zawijając to w obietnicę.
np.
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); } }); }
źródło
EDYTUJ : Żądanie pobierania będzie nadal działało w tle i najprawdopodobniej zarejestruje błąd w konsoli.
Rzeczywiście
Promise.race
podejście jest lepsze.Zobacz ten link, aby zapoznać się z Promise.race ()
Wyścig oznacza, że wszystkie obietnice zostaną uruchomione w tym samym czasie, a wyścig zostanie zatrzymany, gdy tylko jedna z obietnic zwróci wartość. Dlatego zostanie zwrócona tylko jedna wartość . Możesz również przekazać funkcję do wywołania, jeśli upłynie limit czasu pobierania.
fetchWithTimeout(url, { method: 'POST', body: formData, credentials: 'include', }, 5000, () => { /* do stuff here */ });
Jeśli to wzbudzi Twoje zainteresowanie, możliwa implementacja to:
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; }); }
źródło
Możesz utworzyć opakowanie timeoutPromise
function timeoutPromise(timeout, err, promise) { return new Promise(function(resolve,reject) { promise.then(resolve,reject); setTimeout(reject.bind(null,err), timeout); }); }
Następnie możesz zawrzeć dowolną obietnicę
timeoutPromise(100, new Error('Timed Out!'), fetch(...)) .then(...) .catch(...)
W rzeczywistości nie anuluje podstawowego połączenia, ale pozwoli ci przekroczyć limit czasu dla obietnicy.
Odniesienie
źródło
Jeśli nie skonfigurowałeś limitu czasu w swoim kodzie, będzie to domyślny limit czasu żądania Twojej przeglądarki.
1) Firefox - 90 sekund
Wpisz
about:config
adres URL przeglądarki Firefox. Znajdź wartość odpowiadającą kluczowinetwork.http.connection-timeout
2) Chrome - 300 sekund
Źródło
źródło
fetchTimeout (url,options,timeout=3000) { return new Promise( (resolve, reject) => { fetch(url, options) .then(resolve,reject) setTimeout(reject,timeout); }) }
źródło
Korzystając z c-promise2 lib, anulowane pobieranie z limitem czasu może wyglądać następująco ( Live jsfiddle demo ):
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
Ten kod jako pakiet npm cp-fetch
źródło