前端网络层性能优化

前言

在数字时代,速度已成为互联网体验的关键。用户对网页加载时间的容忍度越来越低,每一毫秒的延迟都可能导致用户的流失。根据谷歌的研究,页面加载时间超过3秒的网站,其跳出率会增加120%。在这个以用户为中心的网络世界里,性能优化不再是一个选项,而是必须。

DNS相关优化

用户输入网址后,第一步是解析网址,浏览器需要将这个域名转换为机器可读的IP地址,这是通过DNS(domain name system)查询来完成。

1. DNS缓存

通常我们的操作系统和浏览器已经自动做了相关缓存

  • 浏览器缓存:现代浏览器会缓存DNS查询结果,减少同一域名的重复查询。

  • 操作系统缓存:操作系统也会缓存DNS查询结果,通常可以通过命令查看和管理,如ipconfig /displaydns(Windows)或sudo dscacheutil -cachedump -entries host(macOS)。

  • DNS解析器缓存:本地网络的DNS解析器通常也会缓存查询结果,提高局域网内的查询速度。

2. 减少外部资源引用和开启DNS域名预解析
  • 条件允许的情况下,合并CSS和JS,减少外部文件请求次数

  • 尽可能使用同一个域名下的资源,避免跨域请求

  • 对于跨域资源,可以通过dns-prefetch来开启DNS预解析。

    <link rel="dns-prefetch" href="https://fonts.googleapis.com/" />
    

    更多关于dns-prefetch的信息请点击这里[1]

3. 启用CDN加速

CDN通过在全球分布的服务器缓存内容,提供更快速的访问。CDN服务提供商通常也提供优化的DNS服务,将用户的DNS查询定向到离用户最近的服务器节点,进一步减少延迟。

HTTP相关优化

解析完域名之后,自然就是开始HTTP连接。在这个阶段,我们能做的事情变得更多了。

1. 关于http协议

http协议总是在不断的升级优化中,更高版本的http协议总能带来更好的性能,根据你项目与用户的实际情况,尽可能的升级到合理的版本。这里不赘述http1/2/3之间的区别,想要了解的出门左转问问GPT。

1.1 http1.1的优化

如果你评估了你的项目确实无法升级到http2或更高,那么可以考虑以下优化

  • 减少请求次数:举个例子,webpack中有个SplitChunksPlugin的插件, 用于分割代码生成产物的,我们可以利用这个插件控制我们的生成物,例如像Vue、Vue-router、Vuex、以及我们用到的一些基础依赖都打包成一个js,对于仅在某些页面引用的依赖进行单独拆分便于按需加载。其他的还有使用雪碧图、将小图片转为base64内嵌到js或html里等手段。

  • 持久连接(Keep-Alive):确保服务器和客户端都支持持久连接,允许在同一个TCP连接上进行多次请求和响应。

  • 设置缓存头:合理设置HTTP缓存头(如Cache-Control、Expires、ETag),利用浏览器缓存减少对相同资源的重复请求。(这不限于http1.1)

  • 在HTTP/1.x中,大多数浏览器对单个域名最多只能同时打开6-8个TCP连接。为了提高并发加载资源的能力,可以将资源分布到多个子域名上,每个子域名可以独立建立连接,从而增加总的并发连接数。

1.2 http2的优化
  • 在HTTP/2中,通过二进制分帧和多路复用技术,可以在同一个TCP连接上并行传输多个请求和响应。所以与http1.1不太一样的,我们应该对js、css进行更加细致的切割,方便我们更加精细的控制按需加载,减少需要加载的文件大小,提高首屏速度。

  • 服务器推送:利用HTTP/2的服务器推送(Server Push)功能,服务器可以主动向客户端推送资源,减少客户端请求的次数。例如,在Nginx中配置:

    http {server {location / {http2_push_preload on;add_header Link "<https://example.com/style.css>; rel=preload; as=style";}}
    }
    
  • 由于域名分片是有一定代价的(dns查询,tcp链接建立、缓存策略的效率等),http2支持多路复用,已经无需域名分片了,如果有使用域名分片,在升级到http2以后尽可能的将资源移至同一域名下。

2. 请求包大小优化

显而易见,减少我们请求的资源的总大小是一个非常直观的优化指标。

2.1 启用传输压缩算法

尽管nginx等服务端程序提供了像gzipbrotli等压缩功能,但是这会带来不小的服务端开销,我们可以提前在代码打包时进行压缩。

  • webpack需要安装CompressionWebpackPlugin[2]这个插件

    const CompressionPlugin = require('compression-webpack-plugin');module.exports = {// 其他配置项...plugins: [// Gzip 压缩new CompressionPlugin({algorithm: 'gzip',filename: '[path][base].gz',test: /.(js|css|html|svg)$/,threshold: 10240,minRatio: 0.8}),// Brotli 压缩new CompressionPlugin({algorithm: 'brotliCompress',filename: '[path][base].br',test: /.(js|css|html|svg)$/,compressionOptions: { level: 11 },threshold: 10240,minRatio: 0.8})],
    };
    
  • vite需要安装vite-plugin-compression[3]这个插件

    import { defineConfig } from 'vite';
    import compression from 'vite-plugin-compression';export default defineConfig({plugins: [// Gzip 压缩compression({algorithm: 'gzip',ext: '.gz', // 输出的文件名后缀threshold: 10240, // 只处理比这个字节大的文件deleteOriginFile: false // 是否删除源文件}),// Brotli 压缩compression({algorithm: 'brotliCompress',ext: '.br', // 输出的文件名后缀threshold: 10240, // 只处理比这个字节大的文件deleteOriginFile: false // 是否删除源文件})]
    });
    
2.2 按需加载
  • 代码分割(Code Splitting):webpack和vite都是使用import()动态导入语法,轻松实现代码分割,实现按需加载。如果需要更加精确的控制代码分割,还可以使用SplitChunksPlugin(webpack)output.manualChunks(rollup/vite)

  • 单页应用的路由懒加载

    react:

    const LazyComponent = React.lazy(() => import('./LazyComponent'));function App() {return (<Suspense fallback={<div>Loading...</div>}><LazyComponent /></Suspense>);
    }
    

    vue:

    const routes = [{path: '/about',component: () => import('./components/About.vue')}
    ];
    
  • 图片懒加载:

    • 原生懒加载:使用 loading="lazy" 属性可以原生支持图片和 iframe 的懒加载

      <img src="large-image.jpg" loading="lazy" alt="Lazy Loaded Image">
      
    • Intersection Observer API:用于懒加载图片、视频、iframe 等资源。

      const imgObserver = new IntersectionObserver((entries, observer) => {entries.forEach(entry => {if (entry.isIntersecting) {const img = entry.target;img.src = img.dataset.src;observer.unobserve(img);}});
      });document.querySelectorAll('img[data-src]').forEach(img => {imgObserver.observe(img);
      });
      
  • 按需加载第三方库:例如lodash替换为lodash-es, 像 element-ui等UI库使用按需导入组件的方式去使用。

3. HTTP缓存
3.1 强缓存
  • Expires: 定义资源过期的具体时间点。浏览器会在该时间点之前使用缓存的资源,而不访问服务器。缺点是由于使用的是具体的时间戳,可能会受到客户端时间不准确的影响

    Expires: Wed, 21 Oct 2024 07:28:00 GMT
    
  • Cache-Control:优先级高于 Expires 头。它可以通过多种指令控制缓存行为,包括设置缓存的最大有效期(max-age)、指定资源是公共还是私有缓存(public/private)、禁止缓存(no-cache)、以及禁止存储(no-store)等。

    Cache-Control: max-age=31536000
    
3.2 协商缓存
  • Last-ModifiedIf-Modified-Since: 首次访问时返回的请求头Last-Modified代表资源最后修改时间,后续请求会作为If-Modified-Since的值发送到服务端,服务端会通过判断这个值与资源最后修改时间是否一致,如果一致则返回 304 NOT_MODIFY,不传输资源内容,否则返回200并传输资源内容。

  • ETagIf-None-Match: etag是服务端生成的唯一标识符(通常是资源的哈希值),后续请求中作为If-None-Match的值发送到服务端,服务端判断资源是否修改。由于Last-Modified基于时间并且精度为秒,所以可能没那么精确;etag更加精确但是由于是实时计算资源的哈希值,所以服务端压力更大。

3.3 强缓存与协商缓存的配合使用

上述两种缓存方式并不是互斥选项,可以配合使用。例如配置一定时间的强缓存,强缓存失效后进行协商缓存查看资源是否修改,如无修改可以继续使用缓存资源。

Cache-Control: max-age=31536000
Last-Modified: Wed, 21 Oct 2024 07:28:00 GMT// 后续请求
If-Modified-Since: Wed, 21 Oct 2024 07:28:00 GMT
3.4 service worker

Service Worker 是一种在浏览器后台运行的脚本,可以拦截和处理网络请求,从而实现缓存和离线访问等功能。通过 Service Worker,你可以控制资源的缓存策略,包括静态资产和动态请求。

4. 浏览器缓存
4.1 cookies

Cookies 是一种在客户端(浏览器)存储小量(一般是4KB)数据的机制,用于在多个请求和页面访问之间维持状态信息。它们在 Web 开发中被广泛使用,可以存储用户的会话信息、用户偏好设置、跟踪用户行为等。

4.2 web storage

是浏览器提供的两组api localStoragesessionStorage,用于存储键值对,大小通常为5M~10M。不同点在于

  • localStorage为永久存储,不主动删除不会消失,sessionStorage会随会话销毁而消失

  • localStorage可以跨窗口使用,sessionStorage不行

4.3 IndexedDB

IndexedDB 是一种浏览器内建的 NoSQL 数据库,允许在客户端存储大量结构化的数据。与 Web Storage API(localStorage 和 sessionStorage)相比,IndexedDB 提供了更多的功能和灵活性,适合存储复杂数据和执行更复杂的查询操作。

  • 存储容量更大,根据不同浏览器的实现,通常有几百M到上G

  • 支持更多的数据格式例如对象、数组等,不限于字符串

  • 支持事务、索引等

  • 异步API,不阻塞渲染,通过promise返回

本文转载于稀土掘金技术社区,作者:翔啊翔阿翔

原文链接:https://juejin.cn/post/7402204612143497226

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/53974.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Git换行符自动转换参数core.autocrlf的用法

core.autocrlf 是 Git 中用于控制换行符自动转换的配置选项。它有以下几个可能的值&#xff1a; 1. true 作用&#xff1a;在 checkin 时将 CRLF 转换为 LF&#xff0c;在 checkout 时将 LF 转换为 CRLF。适用场景&#xff1a;适用于 Windows 用户&#xff0c;希望在本地文件…

LineageOS刷机教程

版权归作者所有&#xff0c;如有转发&#xff0c;请注明文章出处&#xff1a;https://cyrus-studio.github.io/blog/ LineageOS 是一个基于 Android 开源项目&#xff08;AOSP&#xff09;的开源操作系统&#xff0c;主要由社区开发者维护。它起源于 CyanogenMod 项目&#xff…

10年Python程序员教你多平台采集10万+电商数据【附实例】

10万级电商数据采集需要注意什么&#xff1f; 在进行10万级电商数据采集时&#xff0c;有许多关键因素需要注意&#xff1a; 1. 采集平台覆盖&#xff1a;确保可以覆盖主流的电商平台&#xff0c;如淘宝、天猫、京东、拼多多等。 2. 数据字段覆盖&#xff1a;检查是否可以对平…

go 笔记

数据结构与 方法&#xff08;增删改查&#xff09; 安装goland,注意版本是2024.1.1&#xff0c;不是2024.2.1&#xff0c;软件下载地址也在链接中提供了 ‘go’ 不是内部或外部命令&#xff0c;也不是可运行的程序 或批处理文件。 在 Windows 搜索栏中输入“环境变量”&#…

架构理论碰撞:对比TOGAF、Zachman、DODAF和FEAF等主流架构框架

信息架构框架对比分析&#xff1a;选择适合企业的最佳方案 在企业数字化转型过程中&#xff0c;信息架构的设计与实施至关重要。成功的信息架构能够有效地支持业务流程优化&#xff0c;提升数据管理效率&#xff0c;推动技术创新。然而&#xff0c;不同的信息架构框架各有其独…

linux gcc 静态库的简单介绍

在 Linux 上&#xff0c;使用 GCC 编译器来创建和调用静态库时&#xff0c;涉及的实现原理和调用机制可以分为以下几个步骤&#xff1a; 1. 静态库的创建 静态库&#xff08;通常以 .a 结尾&#xff09;是由多个目标文件&#xff08;.o 文件&#xff09;打包在一起的归档文件…

判断线是否相交、判断点是否在线上、求线相交交点

先定义个点、线结构 typedef struct tagStruVertex {double x;double y;double distanceTo(const tagStruVertex& point) const{return sqrt((x - point.x) * (x - point.x) (y - point.y) * (y - point.y));}bool equal(const tagStruVertex& point) const{if (poin…

COMTRADE binary数据文件解析

一、COMTRADE 二进制文件的解析需要用到cfg文件中的配置信息&#xff0c;以及dat文件中的数据。 二、cfg文件 1、cfg文件整体配置 2、cfg文件实例 厂站名&#xff0c;记录装置&#xff0c;COMTRADE标准版本年号 SMARTSTATION,IED123,2013 总通道数&#xff0c;模拟通道编号&…

记录word转xml文件踩坑

word文件另存为xml文件后&#xff0c;xml文件乱码 解决方法&#xff1a; 1.用word打开.docx文件 2.另存为xml文件 3.点击工具 -> Web选项 -> 编码&#xff0c;选择UTF-8 4.点击确定 5.使用notpad打开xml文件 6.使用xml tool进行xml格式化即可。

uniapp小程序,使用腾讯地图获取定位

本篇文章分享一下在实际开发小程序时遇到的需要获取用户当前位置的问题&#xff0c;在小程序开发过程中经常使用到获取定位功能。uniapp官方也提供了相应的API供我们使用。 官网地址&#xff1a;uni.getLocation(OBJECT)) 官网获取位置的详细介绍这里就不再讲述了&#xff0c;大…

安宝特方案 | 医疗AR眼镜,重新定义远程会诊体验

【AR眼镜&#xff1a;重新定义远程会诊体验】 在快速发展的医疗领域&#xff0c;安宝特医疗AR眼镜以其尖端技术和创新功能&#xff0c;引领远程会诊的未来&#xff0c;致力于为为医生和患者带来更高效、精准和无缝的医疗体验。 探索安宝特医疗AR眼镜如何在医疗行业中引领新风潮…

视频推拉流/直播点播EasyDSS平台安装失败并报错“install mediaserver error”是什么原因?

TSINGSEE青犀视频推拉流/直播点播EasyDSS平台支持音视频采集、视频推拉流、播放H.265编码视频、存储、分发等视频能力服务&#xff0c;在应用场景中可实现视频直播、点播、转码、管理、录像、检索、时移回看等。此外&#xff0c;平台还支持用户自行上传视频文件&#xff0c;也可…

Gitbook 本地安装教程

Gitbook 本地安装教程 安装 node [nodejs的v10.21.0版本&#xff0c;下载地址&#xff1a;https://nodejs.org/dist/v10.21.0/node-v10.21.0-x64.msi] 其他版本有问题 npmnpm install -g gitbook-cligitbook init [初始化目录结构]gitbook build [编译]gitbook serve [运行] …

MongoDB日志级别

日志 查看当前的日志级别 根据你提供的 MongoDB 命令结果&#xff0c;命令 db.adminCommand({ getParameter: "logComponentVerbosity" }) 返回了 "ok" : 0&#xff0c;这意味着命令执行失败&#xff0c;没有成功获取到日志级别的配置信息。错误信息 &quo…

【项目一】基于pytest的自动化测试框架———解读requests模块

解读python的requests模块 什么是requests模块基础用法GET与POST的区别数据传递格式会话管理与持久性连接处理相应结果应对HTTPS证书验证错误处理与异常捕获 这篇blog主要聚焦如何使用 Python 中的 requests 模块来实现接口自动化测试。下面我介绍一下 requests 的常用方法、数…

【JAVA入门】Day45 - 压缩流 / 解压缩流

【JAVA入门】Day45 - 压缩流 / 解压缩流 文章目录 【JAVA入门】Day45 - 压缩流 / 解压缩流一、解压缩流二、压缩流 在文件传输过程中&#xff0c;文件体积比较大&#xff0c;传输较慢&#xff0c;因此我们发明了一种方法&#xff0c;把文件里的数据压缩到一种压缩文件中&#x…

[苍穹外卖]-10WebSocket入门与实战

WebSocket WebSocket是基于TCP的一种新的网络协议, 实现了浏览器与服务器的全双工通信, 即一次握手,建立持久连接,双向数据传输 区别 HTTP是短连接, WebSocket是长连接HTTP单向通信, 基于请求响应模型WebSocket支持双向通信 相同 HTTP和WebSocket底层都是TCP连接 应用场景…

JVM 调优篇7 调优案例1-堆空间的优化解决

一 jvm优化 1.1 优化实施步骤 1)减少使用全局变量和大对象&#xff1b; 2)调整新生代的大小到最合适&#xff1b; 3)设置老年代的大小为最合适&#xff1b; 4)选择合适的GC收集器&#xff1b; 1.2 关于GC优化原则 多数的Java应用不需要在服务器上进行GC优化&#xff1b…

Java中的Lambda表达式和Stream API详解

在现代Java开发中&#xff0c;Lambda表达式和Stream API是简化代码、提高可读性和开发效率的关键工具。Java 8引入的这两大功能不仅增强了语言的表达力&#xff0c;还大幅提升了处理集合和数据流的能力。本文将详细解析Lambda表达式和Stream API的使用方法&#xff0c;并结合实…

FreeRTOS常用API接口函数

提示&#xff1a;FreeRTOS常用API接口函数&#xff1a;并对部分参数附上自己的解释,后面继续补充 FreeRTOS常用API接口函数 1.任务相关的API1.1 创建任务&#xff1a;xTaskCreate1.2 开启任务调度器函数&#xff1a;vTaskStartScheduler1.3 任务的删除&#xff1a;vTaskDelete1…