在现代的前端开发中,网络请求的超时处理是一个非常重要的功能。它确保了当请求耗时过长时,应用能够及时做出响应,而不是一直等待服务器的响应。虽然 Fetch API 本身没有内置的超时机制,但可以通过多种方式实现这一功能。
使用 Promise.race 实现超时控制
Promise.race
是一个非常有用的函数,它可以接收多个 Promise,并返回一个最先完成的 Promise 的结果。利用这一点,我们可以创建一个带有超时机制的请求。
示例代码
// javascriptcn.com 代码示例 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
函数。
示例代码
// javascriptcn.com 代码示例 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
结构来捕获并处理可能发生的错误,包括超时错误和网络请求错误。
使用自定义的超时逻辑
除了上述两种方法,我们也可以完全自己实现超时逻辑。例如,我们可以在发送请求后立即启动一个定时器,如果请求在一定时间内未完成,则认为请求超时,并执行相应的操作。
示例代码
// javascriptcn.com 代码示例 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 请求超时设置的方法。每种方法都有其优缺点,可以根据实际需求选择最适合的方式。