面试题-当QPS达到峰值时, 前端该如何处理?

91 阅读4分钟

当QPS(Queries Per Second,每秒查询率)达到峰值时,前端可以从多个方面进行处理,以保证系统的稳定性、响应速度和用户体验。以下是一些常见的处理策略:

1. 缓存策略

  • 本地存储缓存
    • 原理:利用浏览器的本地存储(如localStoragesessionStorage)来缓存一些不经常变化的数据,例如静态配置信息、用户的基本信息等。当QPS达到峰值时,前端可以直接从本地存储中获取这些数据,而不需要向服务器发送请求,从而减少服务器的压力。
    • 示例代码
// 存储数据到localStorage
localStorage.setItem('userInfo', JSON.stringify({ name: 'John', age: 30 }));

// 从localStorage获取数据
const userInfo = JSON.parse(localStorage.getItem('userInfo'));
  • 内存缓存
    • 原理:在JavaScript中,可以使用变量来缓存一些临时数据。例如,在单页面应用中,可以在组件的状态中缓存一些已经获取过的数据,避免重复请求。
    • 示例代码
let cachedData = null;

function getData() {
    if (cachedData) {
        return Promise.resolve(cachedData);
    }
    return fetch('/api/data')
      .then(response => response.json())
      .then(data => {
            cachedData = data;
            return data;
        });
}

2. 节流和防抖

  • 节流
    • 原理:限制事件的触发频率,确保在一定时间内只执行一次请求。例如,在用户滚动页面时,可能会触发大量的滚动事件,如果每次滚动都向服务器发送请求,会导致QPS急剧上升。使用节流可以减少请求的次数。
    • 示例代码
function throttle(func, delay) {
    let timer = null;
    return function() {
        if (!timer) {
            func.apply(this, arguments);
            timer = setTimeout(() => {
                timer = null;
            }, delay);
        }
    };
}

window.addEventListener('scroll', throttle(() => {
    // 发送请求的代码
    console.log('Scroll event triggered');
}, 200));
  • 防抖
    • 原理:在一定时间内,只有最后一次触发事件才会执行请求。例如,在用户输入搜索关键词时,每次输入都会触发搜索请求,使用防抖可以避免在用户输入过程中频繁发送请求,只有在用户停止输入一段时间后才发送请求。
    • 示例代码
function debounce(func, delay) {
    let timer = null;
    return function() {
        clearTimeout(timer);
        timer = setTimeout(() => {
            func.apply(this, arguments);
        }, delay);
    };
}

const input = document.getElementById('search-input');
input.addEventListener('input', debounce(() => {
    // 发送搜索请求的代码
    console.log('Search input changed');
}, 300));

3. 异步加载和懒加载

  • 异步加载
    • 原理:将一些非关键资源(如脚本、样式表等)进行异步加载,避免阻塞页面的渲染。这样可以提高页面的加载速度,同时减少首屏加载时的请求数量。
    • 示例代码
<!-- 异步加载脚本 -->
<script async src="script.js"></script>
  • 懒加载
    • 原理:对于一些在页面初始加载时不需要立即显示的资源(如图片、组件等),采用懒加载的方式,只有当这些资源进入用户的可视区域时才进行加载。这样可以减少初始加载时的请求数量,降低QPS压力。
    • 示例代码(图片懒加载)
<img data-src="image.jpg" class="lazyload">
<script>
    const lazyImages = document.querySelectorAll('.lazyload');
    const observer = new IntersectionObserver((entries, observer) => {
        entries.forEach(entry => {
            if (entry.isIntersecting) {
                const img = entry.target;
                img.src = img.dataset.src;
                observer.unobserve(img);
            }
        });
    });
    lazyImages.forEach(img => {
        observer.observe(img);
    });
</script>

4. 错误处理和降级策略

  • 错误处理
    • 原理:在前端代码中添加完善的错误处理机制,当请求失败时,能够给用户友好的提示,同时避免因为错误导致页面崩溃。
    • 示例代码
fetch('/api/data')
  .then(response => {
        if (!response.ok) {
            throw new Error('Network response was not ok');
        }
        return response.json();
    })
  .then(data => {
        // 处理数据
    })
  .catch(error => {
        console.error('Fetch error:', error);
        // 给用户提示
        alert('Failed to fetch data. Please try again later.');
    });
  • 降级策略
    • 原理:当QPS达到峰值时,为了保证系统的稳定性,可以采用降级策略,例如减少一些不必要的功能或展示简化版的页面。例如,在高并发情况下,关闭一些实时更新的功能,只展示静态数据。

5. 预加载

  • 原理:在用户可能进行某些操作之前,提前加载相关的资源。例如,在用户浏览商品列表时,预加载下一页的商品数据,当用户点击“下一页”时,可以直接从本地获取数据,减少请求时间和服务器压力。
  • 示例代码
// 预加载下一页数据
function preloadNextPage() {
    const nextPageUrl = '/api/products?page=2';
    fetch(nextPageUrl)
      .then(response => response.json())
      .then(data => {
            // 缓存数据
            localStorage.setItem('nextPageData', JSON.stringify(data));
        });
}

// 在合适的时机调用预加载函数
window.addEventListener('scroll', () => {
    if (isNearBottom()) {
        preloadNextPage();
    }
});

通过以上策略,前端可以在QPS达到峰值时,有效地减少请求数量、提高响应速度,从而保证系统的稳定性和用户体验。