Время ожидания запроса API-запроса?
У меня есть запрос fetch-api
POST
:
fetch(url, {
method: 'POST',
body: formData,
credentials: 'include'
})
Я хочу знать, что такое тайм-аут по умолчанию для этого? и как мы можем установить его на определенное значение, например, 3 секунды или неопределенные секунды?
Ответы
Ответ 1
Он не имеет заданного значения по умолчанию; спецификация не обсуждает тайм-ауты вообще.
Вы можете реализовать свою собственную оболочку тайм-аута для обещаний в целом:
// 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
Ответ 2
Мне очень нравится чистый подход от этой сущности, используя 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
})
Ответ 3
Используя синтаксис прерывания, вы сможете сделать:
const controller = new AbortController();
const signal = controller.signal;
const fetchPromise = fetch(url, {signal});
// 5 second timeout:
const timeoutId = setTimeout(() => controller.abort(), 5000);
fetchPromise.then(response => {
// completed request before timeout fired
// If you only wanted to timeout the request, not the response, add:
// clearTimeout(timeoutId);
})
Смотрите страницу AbortController на MDN.
Ответ 4
в 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);
}
});
}
Ответ 5
EDIT: запрос на выбор по-прежнему будет работать в фоновом режиме и, скорее всего, зарегистрирует ошибку в вашей консоли.
Действительно, подход 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(path, request),
timer
]).then(response) {
if (response.timeout) {
onTimeout();
}
return response;
}
}
Ответ 6
Вы можете создать оболочку 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(...)
Это на самом деле не отменит базовое соединение, но позволит вам тайм-аут обещания.
Ссылка
Ответ 7
fetchTimeout (url,options,timeout=3000) {
return new Promise( (resolve, reject) => {
fetch(url, options)
.then(resolve,reject)
setTimeout(reject,timeout);
})
}
Ответ 8
Основываясь на превосходном ответе Enda, я создал полезную вспомогательную функцию.
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
}
});
Надеюсь, это поможет.