news 2026/5/12 23:32:09

网络请求优化实战:让你的应用加载更快

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
网络请求优化实战:让你的应用加载更快

网络请求优化实战:让你的应用加载更快

大家好,我是蔓蔓。在大厂时,我负责过项目的性能优化,网络请求往往是瓶颈。今天我来和大家分享网络请求优化的实战技巧。

请求合并

// 1. 批量请求 async function fetchUsers(ids: number[]) { const response = await fetch(`/api/users?ids=${ids.join(',')}`); return response.json(); } // 2. 时间窗口合并 class RequestBatcher { constructor() { this.queue = []; this.timer = null; this.batchWindow = 50; // 50ms内的请求合并 } add(request) { this.queue.push(request); if (!this.timer) { this.timer = setTimeout(() => { this.executeBatch(); }, this.batchWindow); } } executeBatch() { const requests = this.queue; this.queue = []; this.timer = null; // 发送批量请求 fetchUsers(requests.map(r => r.id)).then(results => { requests.forEach((req, index) => { req.resolve(results[index]); }); }).catch(errors => { requests.forEach(req => req.reject(errors)); }); } } const batcher = new RequestBatcher(); // 使用 function getUser(id: number) { return new Promise((resolve, reject) => { batcher.add({ id, resolve, reject }); }); } // 同一时间内的多次调用会被合并 getUser(1); getUser(2); getUser(3);

请求缓存

class RequestCache { constructor(ttl = 5 * 60 * 1000) { // 默认5分钟 this.cache = new Map(); this.ttl = ttl; } get(key: string) { const entry = this.cache.get(key); if (!entry) return null; if (Date.now() - entry.timestamp > this.ttl) { this.cache.delete(key); return null; } return entry.value; } set(key: string, value: any) { this.cache.set(key, { value, timestamp: Date.now() }); } generateKey(url: string, options = {}) { return `${url}-${JSON.stringify(options)}`; } } const cache = new RequestCache(); // 缓存装饰器 async function fetchWithCache(url: string, options = {}) { const key = cache.generateKey(url, options); const cached = cache.get(key); if (cached) { return cached; } const response = await fetch(url, options); const data = await response.json(); cache.set(key, data); return data; }

请求取消

// 使用AbortController class RequestManager { constructor() { this.abortControllers = new Map(); } fetch(url: string, options = {}) { const abortController = new AbortController(); const signal = abortController.signal; this.abortControllers.set(url, abortController); const promise = fetch(url, { ...options, signal }).finally(() => { this.abortControllers.delete(url); }); return promise; } cancel(url: string) { const controller = this.abortControllers.get(url); if (controller) { controller.abort(); this.abortControllers.delete(url); } } cancelAll() { this.abortControllers.forEach((controller) => { controller.abort(); }); this.abortControllers.clear(); } } // 使用示例 const manager = new RequestManager(); // 发起请求 manager.fetch('/api/data'); // 路由切换时取消 router.beforeEach((to, from, next) => { manager.cancelAll(); next(); });

预加载与懒加载

// 预加载关键资源 function preloadResources() { // 预加载字体 const fontLink = document.createElement('link'); fontLink.rel = 'preload'; fontLink.as = 'font'; fontLink.href = '/fonts/my-font.woff2'; document.head.appendChild(fontLink); // 预加载关键数据 fetch('/api/init-data'); } // 图片懒加载 const imageObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; img.src = img.dataset.src; imageObserver.unobserve(img); } }); }); document.querySelectorAll('img[data-src]').forEach(img => { imageObserver.observe(img); }); // 路由预加载 const router = { navigate(to) { // 预加载下一个页面的资源 if (to === 'dashboard') { import('./dashboard.js'); // 预加载模块 fetch('/api/dashboard-data'); // 预加载数据 } } };

请求重试与降级

async function fetchWithRetry(url: string, options = {}, retries = 3) { let lastError; for (let i = 0; i < retries; i++) { try { const response = await fetch(url, { ...options, signal: options.signal }); if (response.ok) { return response; } // 只有5xx错误重试 if (response.status < 500) { throw new Error(`HTTP ${response.status}`); } } catch (error) { lastError = error; // 指数退避重试 await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000)); } } // 降级策略 if (options.fallback) { console.warn('Falling back to static data'); return new Response(JSON.stringify(options.fallback)); } throw lastError; } // 使用示例 fetchWithRetry('/api/data', { fallback: { items: [] } // 降级数据 });

压缩与优化

// 1. 使用压缩 // 服务端配置gzip/brotli // 2. 选择合适的图片格式 // 使用WebP、AVIF等现代格式 // 3. 图片压缩 // 压缩工具:TinyPNG, Squoosh // 4. 减少请求大小 function minimizeRequest(data) { // 只发送必要字段 const { id, name, ...rest } = data; return { id, name }; } // 5. 使用数据节流 class Throttler { constructor(interval = 2000) { this.lastTime = 0; this.interval = interval; } throttle(fn) { const now = Date.now(); if (now - this.lastTime >= this.interval) { fn(); this.lastTime = now; } } }

总结

网络请求优化是一个系统工程,需要从请求合并、缓存策略、取消机制、预加载、重试降级等多个方面综合考虑。根据实际场景选择合适的优化策略,能显著提升应用的性能和用户体验。

技术应当有温度,更快的响应能让用户感受到你的用心。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/12 23:30:09

如何用91160-cli实现医疗挂号自动化:技术原理与实战指南

如何用91160-cli实现医疗挂号自动化&#xff1a;技术原理与实战指南 【免费下载链接】91160-cli 健康160全自动挂号脚本&#xff0c;捡漏神器 项目地址: https://gitcode.com/gh_mirrors/91/91160-cli 医疗挂号自动化已成为解决医院预约难题的技术方案&#xff0c;91160…

作者头像 李华
网站建设 2026/5/12 23:26:06

VR大空间:沉浸式数字体验引领新时代科普与教育升级

随着虚拟现实技术的不断成熟&#xff0c;传统展示与教学模式正迎来深度变革。其中&#xff0c;VR大空间凭借多人同步体验、自由行走、强沉浸感等优势&#xff0c;逐渐成为党建教育、法治宣传、消防科普、禁毒教育等领域的重要数字化载体。通过真实还原场景、强化互动体验&#…

作者头像 李华
网站建设 2026/5/12 23:25:08

实验记录-农药种衣剂

1.显色度取决于种子颗粒大小&#xff0c;种子越大&#xff0c;则显色越差&#xff1b;2.需加入增稠剂

作者头像 李华
网站建设 2026/5/12 23:24:08

终极虚拟机检测指南:5种方法精准识别虚拟环境

终极虚拟机检测指南&#xff1a;5种方法精准识别虚拟环境 【免费下载链接】VMDE Source from VMDE paper, adapted to 2015 项目地址: https://gitcode.com/gh_mirrors/vm/VMDE VMDE&#xff08;Virtual Machine Detection Enhanced&#xff09; 是一款开源的专业级虚拟…

作者头像 李华
网站建设 2026/5/12 23:21:31

Odoo 19 项目模块功能操作指南:项目定期任务工作流程概述

Odoo 19 项目模块定期任务工作流程概述 对于管理多个项目的企业而言&#xff0c;高效的任务管理至关重要。企业可借助定期任务功能梳理重复性工作&#xff0c;既能确保任务按时完成&#xff0c;也能减少人工操作。每周例会、月度报告、不定期维护工作等都属于定期任务范畴。在 …

作者头像 李华
网站建设 2026/5/12 23:19:20

工程师的3D打印入门指南:从免费软件选型到全流程实战

1. 从“想要”到“拥有”&#xff1a;一位工程师的3D打印机选型心路作为一个在电子设计领域摸爬滚打了十几年的老工程师&#xff0c;我自认对EDA工具、电路仿真这些玩意儿还算得心应手。但当我第一次把目光投向桌面上的那个空位&#xff0c;想象着一台能“无中生有”吐出实体零…

作者头像 李华