Skip to Content

面试导航 - 程序员面试题库大全 | 前端后端面试真题 | 面试

场景题NEW在切换已读和未读 Tab 时,每次切换都发送请求,快速切换 Tab 会导致什么问题

在进行 Tab 切换 时,一个是 已读 Tab(展示已读列表),另一个是 未读 Tab(展示未读列表)。每次点击一个 Tab 都会发送请求去获取信息。如果用户快速切换按钮,会发生以下几个问题:

1. 请求竞争问题(Race Condition)

当用户快速切换 Tab 时,可能会发生 请求竞争 的问题。具体来说,如果用户迅速点击两个 Tab,前一个 Tab 的请求可能还没有完成,后一个 Tab 的请求已经发出并成功返回。这样,后一个请求的响应可能会覆盖前一个请求的响应,导致展示的数据不一致。

2. 性能问题

每次切换 Tab 都发送请求,尤其是在快速切换时,可能会导致多个并行的请求。大量的网络请求会增加服务器压力,同时会浪费带宽和时间,影响用户体验。

3. 不必要的重新渲染(Re-rendering)

如果每次请求返回后都重新渲染组件(例如列表组件),那么频繁的 Tab 切换会导致页面内容的频繁更新,从而带来性能损失和卡顿问题。

如何解决这些问题:
1. 请求去重(Cancel Previous Request)

我们可以通过 AbortController 来取消前一个未完成的请求,确保只有最新的请求结果会被渲染。

方案:

  • 在每次 Tab 切换时,取消之前未完成的请求,只使用当前 Tab 的请求结果。
let abortController = null; function fetchTabData(tabType) { // 如果有未完成的请求,取消前一个请求 if (abortController) { abortController.abort(); } abortController = new AbortController(); const signal = abortController.signal; fetch(`/api/getData?tab=${tabType}`, { signal }) .then((response) => response.json()) .then((data) => { console.log('Data for', tabType, data); }) .catch((error) => { if (error.name === 'AbortError') { console.log('Request was aborted'); } else { console.error(error); } }); } // 用户点击切换 tab 时调用 document.getElementById('readTab').addEventListener('click', () => fetchTabData('read')); document.getElementById('unreadTab').addEventListener('click', () => fetchTabData('unread'));
2. 去抖或节流(Debouncing or Throttling)

通过 去抖(debounce)节流(throttle) 来控制请求频率,避免快速切换时发送过多请求。

方案:

  • 去抖(debounce):限制频繁点击 Tab 的请求频率,只有用户停止快速点击时才发送请求。
  • 节流(throttle):限制每次请求的间隔,避免在短时间内触发过多请求。
let debounceTimeout = null; function debounceFetchTabData(tabType) { clearTimeout(debounceTimeout); debounceTimeout = setTimeout(() => { fetchTabData(tabType); }, 300); // 延迟 300ms,只有用户停止切换时才发送请求 } document.getElementById('readTab').addEventListener('click', () => debounceFetchTabData('read')); document .getElementById('unreadTab') .addEventListener('click', () => debounceFetchTabData('unread'));
3. 缓存已请求的数据

避免重复请求已经加载过的数据,使用缓存机制,切换 Tab 时可以直接使用缓存数据。

方案:

  • 通过缓存已请求的数据,避免重新发送请求。例如,如果已请求过 已读 数据,则直接从缓存中取出数据而不重新请求。
const cache = {}; function fetchTabData(tabType) { if (cache[tabType]) { // 使用缓存数据 console.log('Using cached data for', tabType, cache[tabType]); } else { fetch(`/api/getData?tab=${tabType}`) .then((response) => response.json()) .then((data) => { cache[tabType] = data; // 缓存数据 console.log('Fetched data for', tabType, data); }); } } document.getElementById('readTab').addEventListener('click', () => fetchTabData('read')); document.getElementById('unreadTab').addEventListener('click', () => fetchTabData('unread'));
4. 优化渲染和状态管理

确保只有当前需要的部分组件重新渲染,避免因状态更新过多导致不必要的渲染,特别是在使用 React、Vue 等框架时,可以采用 虚拟 DOMReact.memo 等技术来避免多余的渲染。

5. 使用 SWR 优化 Tab 切换

SWRStale-While-Revalidate)是一个非常适合处理 Tab 切换时的数据请求 的库,它自动处理 请求去重缓存后台刷新,可以有效解决频繁切换 Tab 时的请求竞争问题和性能问题。

SWR 的优势:
  • 去重请求:SWR 会自动去重重复请求,确保每个数据请求只发起一次。
  • 数据缓存:已经请求过的数据会被缓存,切换 Tab 时直接从缓存中获取数据,避免重复请求。
  • 自动后台刷新:SWR 支持自动刷新数据,保持数据的最新性,而不会影响 UI 渲染。
SWR 示例:
import React, { useState } from 'react'; import useSWR from 'swr'; // 模拟的 API 请求函数 const fetcher = (url) => fetch(url).then((res) => res.json()); const TabSwitcher = () => { const [activeTab, setActiveTab] = useState('read'); // 当前激活的 Tab,默认为已读 Tab // 使用 SWR 来请求数据 const { data: readData, error: readError } = useSWR( activeTab === 'read' ? '/api/read' : null, // 只有在选中已读 Tab 时才请求数据 fetcher, ); const { data: unreadData, error: unreadError } = useSWR( activeTab === 'unread' ? '/api/unread' : null, // 只有在选中未读 Tab 时才请求数据 fetcher, ); // 错误处理 if (readError || unreadError) return <div>加载失败,请重试。</div>; if (!readData && activeTab === 'read') return <div>加载已读数据...</div>; if (!unreadData && activeTab === 'unread') return <div>加载未读数据...</div>; return ( <div> <button onClick={() => setActiveTab('read')}>已读</button> <button onClick={() => setActiveTab('unread')}>未读</button> <div> {activeTab === 'read' ? ( <div> <h2>已读列表</h2> <ul> {readData.map((item) => ( <li key={item.id}>{item.name}</li> ))} </ul> </div> ) : ( <div> <h2>未读列表</h2> <ul> {unreadData.map((item) => ( <li key={item.id}>{item.name}</li> ))} </ul> </div> )} </div> </div> ); }; export default TabSwitcher;
总结:
  1. 请求竞争问题:使用 AbortController 来取消前一个未完成的请求,确保只有最后一个请求的数据被使用。
  2. 避免过多请求:使用 去抖节流 技术,控制请求频率,避免频繁请求。
  3. 缓存已请求数据:对于已请求过的数据,使用缓存机制,避免重复请求。
  4. 优化渲染:减少不必要的重新渲染,提高性能。
  5. SWR 优化:SWR 自动处理请求去重、缓存和后台刷新,能有效提升性能并避免请求竞争。

通过这些优化方法,你可以有效避免 快速切换 Tab 时的卡顿、请求竞争和性能问题,提升用户体验。 SWR 是一个非常适合解决这种问题的库,它能够简化数据请求的管理,提高页面性能和用户体验。

最后更新于:
Copyright © 2025Moment版权所有粤ICP备2025376666