在现代的前端开发中,网络请求的超时处理是一个非常重要的功能。它确保了当请求耗时过长时,应用能够及时做出响应,而不是一直等待服务器的响应。虽然 Fetch API 本身没有内置的超时机制,但可以通过多种方式实现这一功能。
使用 Promise.race 实现超时控制
Promise.race 是一个非常有用的函数,它可以接收多个 Promise,并返回一个最先完成的 Promise 的结果。利用这一点,我们可以创建一个带有超时机制的请求。
示例代码
// www.javascriptcn.com code example
function fetchWithTimeout(resource, options = {}, timeout = 8000) {
const controller = new AbortController();
const signal = controller.signal;
// 创建一个超时的 Promise
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => {
controller.abort();
reject(new Error('请求超时'));
}, timeout);
});
return Promise.race([
fetch(resource, { ...options, signal }),
timeoutPromise,
]);
}
// 使用示例
fetchWithTimeout('https://jsonplaceholder.typicode.com/todos/1', {
method: 'GET'
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('请求失败:', error));在这个例子中,我们首先创建了一个 AbortController,用于在请求超时时取消请求。然后,我们使用 setTimeout 创建了一个超时的 Promise,如果请求超过设定的时间(这里是 8000 毫秒),则调用 controller.abort() 来取消请求,并通过 reject 抛出一个错误。最后,我们使用 Promise.race 来比较请求的 Promise 和超时的 Promise,谁先完成就执行哪个。
使用 async/await 实现超时控制
除了使用 Promise.race,我们还可以利用 async/await 来实现更直观的代码结构。这种方式需要将 Promise 转换成 async 函数。
示例代码
// www.javascriptcn.com code example
async function fetchWithTimeout(url, options = {}, timeout = 8000) {
const controller = new AbortController();
const signal = controller.signal;
// 创建一个超时的 Promise
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => {
controller.abort();
reject(new Error('请求超时'));
}, timeout);
});
try {
const response = await Promise.race([
fetch(url, { ...options, signal }),
timeoutPromise,
]);
return await response.json(); // 如果需要获取 JSON 数据
} catch (error) {
console.error('请求失败:', error);
}
}
// 使用示例
(async () => {
try {
const data = await fetchWithTimeout('https://jsonplaceholder.typicode.com/todos/1', {
method: 'GET'
});
console.log(data);
} catch (error) {
console.error('请求失败:', error);
}
})();在这个例子中,我们将 fetchWithTimeout 函数定义为一个 async 函数。这样可以更方便地使用 await 关键字来等待 Promise 的完成。同时,我们通过 try/catch 结构来捕获并处理可能发生的错误,包括超时错误和网络请求错误。
使用自定义的超时逻辑
除了上述两种方法,我们也可以完全自己实现超时逻辑。例如,我们可以在发送请求后立即启动一个定时器,如果请求在一定时间内未完成,则认为请求超时,并执行相应的操作。
示例代码
// www.javascriptcn.com code example
function fetchWithTimeout(url, options = {}, timeout = 8000) {
return new Promise((resolve, reject) => {
const controller = new AbortController();
const signal = controller.signal;
const timeoutId = setTimeout(() => {
controller.abort();
reject(new Error('请求超时'));
}, timeout);
fetch(url, { ...options, signal })
.then(response => {
clearTimeout(timeoutId); // 清除定时器
resolve(response);
})
.catch(error => {
clearTimeout(timeoutId); // 清除定时器
reject(error);
});
});
}
// 使用示例
fetchWithTimeout('https://jsonplaceholder.typicode.com/todos/1', {
method: 'GET'
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('请求失败:', error));在这个例子中,我们在发送请求之前启动了一个定时器,如果请求在指定的时间内未完成,我们就认为请求超时,并通过 controller.abort() 来取消请求。同时,在请求成功或失败后,我们都会清除定时器,以避免不必要的副作用。
以上就是几种常见的 Fetch API 请求超时设置的方法。每种方法都有其优缺点,可以根据实际需求选择最适合的方式。