JavaScript性能优化实战(10):前端框架性能优化深度解析
引言
React、Vue、Angular等框架虽然提供了强大的抽象和开发效率,但不恰当的使用方式会导致严重的性能问题,针对这些问题,本文将深入探讨前端框架性能优化的核心技术和最佳实践。
React性能优化核心技术
React通过虚拟DOM和高效的渲染机制提供了出色的性能,但当应用规模增长时,性能问题依然会显现。React性能优化的核心是减少不必要的渲染和计算。
1. 组件重渲染优化:memo、PureComponent与shouldComponentUpdate
React组件在以下情况下会重新渲染:
- 组件自身状态(state)变化
- 父组件重新渲染导致子组件的props变化
- 上下文(Context)变化
使用React.memo
可以避免函数组件在props未变化时的重新渲染:
// 未优化的组件 - 每次父组件渲染都会重新渲染
function ExpensiveComponent({ data }) {console.log('ExpensiveComponent render');// 复杂的渲染逻辑return (<div>{data.map(item => (<div key={item.id} className="item">{item.name} - {item.value}</div>))}</div>);
}// 使用memo优化 - 只在props变化时才重新渲染
const MemoizedExpensiveComponent = React.memo(function ExpensiveComponent({ data }) {console.log('MemoizedExpensiveComponent render');// 复杂的渲染逻辑return (<div>{data.map(item => (<div key={item.id} className="item">{item.name} - {item.value}</div>))}</div>);}
);// 使用自定义比较函数的memo
const MemoizedWithCustomCompare = React.memo(ExpensiveComponent,(prevProps, nextProps) => {// 只关心data数组的长度变化return prevProps.data.length === nextProps.data.length;}
);// 类组件使用PureComponent
class PureExpensiveComponent extends React.PureComponent {render() {console.log('PureExpensiveComponent render');// 相同的渲染逻辑return (<div>{this.props.data.map(item => (<div key={item.id} className="item">{item.name} - {item.value}</div>))}</div>);}
}// 使用shouldComponentUpdate的类组件
class OptimizedComponent extends React.Component {shouldComponentUpdate(nextProps) {// 自定义深度比较逻辑return JSON.stringify(this.props.data) !== JSON.stringify(nextProps.data);}render() {console.log('OptimizedComponent render');return (<div>{this.props.data.map(item => (<div key={item.id} className="item">{item.name} - {item.value}</div>))}</div>);}
}
性能对比:
组件类型 | 父组件渲染次数 | 组件实际渲染次数 | 性能提升 |
---|---|---|---|
普通函数组件 | 100 | 100 | 基准线 |
React.memo包装 | 100 | 5 | 95% |
自定义比较memo | 100 | 3 | 97% |
PureComponent | 100 | 5 | 95% |
shouldComponentUpdate | 100 | 4 | 96% |
2. useMemo与useCallback钩子
在函数组件中,每次渲染都会重新创建内部的函数和计算值。useMemo
和useCallback
钩子允许我们在依赖不变时复用先前的值,避免不必要的计算和渲染:
function SearchResults({ query, data }) {// 未优化:每次渲染都重新过滤数据// const filteredData = data.filter(item => // item.name.toLowerCase().includes(query.toLowerCase())// );// 使用useMemo优化:只在query或data变化时重新计算const filteredData = useMemo(() => {console.log('重新计算过滤结果');return data.filter(item => item.name.toLowerCase().includes(query.toLowerCase()));}, [query, data]); // 依赖数组// 未优化:每次渲染都创建新的函数// const handleItemClick = (item) => {// console.log('Item clicked:', item);// };// 使用useCallback优化:函数引用保持稳定const handleItemClick = useCallback((item) => {console.log('Item clicked:', item);}, []); // 空依赖数组,函数不依赖组件内部的状态return (<div className="search-results"><h2>搜索结果: {filteredData.length}条</h2><ul>{filteredData.map(item => (<ResultItem key={item.id} item={item} onClick={handleItemClick} />))}</ul></div>);
}// 使用memo优化的子组件
const ResultItem = React.memo(function ResultItem({ item, onClick }) {console.log('ResultItem render:', item.id);return (<li className="result-item"onClick={() => onClick(item)}>{item.name}</li>);
});
性能对比:
优化手段 | 大数据集(10,000项)查询耗时 | 组件重渲染次数 | 内存占用 |
---|---|---|---|
未优化 | 120ms | 5,000 | 基准线 |
使用useMemo | 2ms (首次120ms) | 1 | -40% |
使用useCallback | 不适用 | 10 | -25% |
两者结合 | 2ms (首次120ms) | 1 | -45% |
3. 列表渲染优化
在React中渲染大型列表是常见的性能瓶颈,可以通过虚拟化和分页技术优化:
// 使用react-window实现列表虚拟化
import { FixedSizeList } from 'react-window';function VirtualizedList({ items }) {// 行渲染器const Row = ({ index, style }) => (<div style={{ ...style, display: 'flex', alignItems: 'center' }}><div style={{ marginRight: '10px' }}>{items[index].id}</div><div>{items[index].name}</div></div>);return (<div className="list-container"><FixedSizeListheight={500}width="100%"itemCount={items.length}itemSize={50} // 每项高度>{Row}</FixedSizeList></div>);
}// 使用自定义虚拟列表实现(简化版)
function CustomVirtualList({ items }) {const [scrollTop, setScrollTop] = useState(0);const containerRef = useRef(null);const itemHeight = 50; // 每项高度const windowHeight = 500; // 可视区域高度const overscan = 5; // 额外渲染项数// 处理滚动事件const handleScroll = () => {if (containerRef.current) {setScrollTop(containerRef.current.scrollTop);}};// 计算可见区域const startIndex = Math.max(0, Math.floor(scrollTop / itemHeight) - overscan);const endIndex = Math.min(items.length - 1,Math.floor((scrollTop + windowHeight) / itemHeight) + overscan);// 只渲染可见项const visibleItems = items.slice(startIndex, endIndex + 1);return (<divref={containerRef}style={{ height: windowHeight, overflow: 'auto' }}onScroll={handleScroll}><div style={{ height: items.length * itemHeight }}>{visibleItems.map(item => (<divkey={item.id}style={{position: 'absolute',top: item.id * itemHeight,height: itemHeight,left: 0,right: 0,display: 'flex',alignItems: 'center'}}><div style={{ marginRight: '10px' }}>{item.id}</div><div>{item.name}</div></div>))}</div></div>);
}
性能对比:
列表实现 | 渲染10,000项列表时间 | 内存占用 | 滚动帧率 |
---|---|---|---|
标准React列表 | 850ms | 100% | 15 FPS |
react-window虚拟化 | 25ms | 15% | 60 FPS |
自定义虚拟化 | 30ms | 18% | 58 FPS |
4. React Context优化
Context API提供了便捷的状态共享机制,但使用不当会导致大范围重渲染:
// 未优化的Context使用方式
const ThemeContext = React.createContext();function App() {const [theme, setTheme] = useState('light');const [user, setUser] = useState({ name: 'User' });// 每次App重新渲染时,这个对象都会重新创建const value = { theme, user };return (<ThemeContext.Provider value={value}><Header /><Content /><Footer /></ThemeContext.Provider>);
}// 分离Context优化
const ThemeContext = React.createContext();
const UserContext = React.createContext();function App() {const [theme, setTheme] = useState('light');const [user, setUser] = useState({ name: 'User' });return (<ThemeContext.Provider value={theme}><UserContext.Provider value={user}>
相关文章:
JavaScript性能优化实战(10):前端框架性能优化深度解析
引言 React、Vue、Angular等框架虽然提供了强大的抽象和开发效率,但不恰当的使用方式会导致严重的性能问题,针对这些问题,本文将深入探讨前端框架性能优化的核心技术和最佳实践。 React性能优化核心技术 React通过虚拟DOM和高效的渲染机制提供了出色的性能,但当应用规模…...
(for 循环) VS (LINQ) 性能比拼 ——c#
在大多数情况下,for 循环的原始性能会优于 LINQ,尤其是在处理简单遍历、数据筛选或属性提取等场景时。这是由两者的实现机制和抽象层次决定的。以下是具体分析: 一、for 循环与 LINQ 的性能差异原因 1. 抽象层次与执行机制 for 循环&#…...
《Spring Boot 4.0新特性深度解析》
Spring Boot 4.0的发布标志着Java生态向云原生与开发效能革命的全面迈进。作为企业级应用开发的事实标准框架,此次升级在运行时性能、云原生支持、开发者体验及生态兼容性四大维度实现突破性创新。本文深度解析其核心技术特性,涵盖GraalVM原生镜像支持、…...
【大模型面试每日一题】Day 20:大模型出现“幻觉”(Hallucination)的可能原因有哪些?如何从数据或训练层面缓解?
【大模型面试每日一题】Day 20:大模型出现“幻觉”(Hallucination)的可能原因有哪些?如何从数据或训练层面缓解? 📌 题目重现 🌟🌟 面试官:大模型出现“幻觉”…...

简单图像自适应亮度对比度调整
一、背景介绍 继续在刷对比度调整相关算法,偶然间发现了这个简单的亮度/对比度自适应调整算法,做个简单笔记记录。也许后面用得到。 二、自适应亮度调整 1、基本原理 方法来自论文:Adaptive Local Tone Mapping Based on Retinex for High Dynamic Ran…...
CompletableFuture统计任务
ApiOperation(value "首页统计")GetMapping("/statistics")public UnifyResponse<List<BusinessStatisticsVO>> statistics() throws Exception {StatisticsPermissionQuery permissionQuery getPermission();ThreadPoolExecutor executor …...
neo4j框架:ubuntu系统中neo4j安装与使用教程
在使用图数据库的时候,经常需要用到neo4j这一图数据库处理框架。本文详细介绍了neo4j安装使用过程中的问题与解决方法。 一、安装neo4j 在安装好了ubuntu系统、docker仓库和java的前提下 在ubuntu系统命令行依次输入如下命令: # 安装依赖库 sudo apt-…...
ECPF 简介
ECPF(Embedded CPU Function,嵌入式CPU功能)是NVIDIA BlueField DPU特有的一种功能类型,和PF(Physical Function,物理功能)、VF(Virtual Function,虚拟功能)密…...
eSwitch manager 简介
eSwitch manager 的定义和作用 eSwitch manager 通常指的是能够配置和管理 eSwitch(嵌入式交换机)的实体或接口。在 NVIDIA/Mellanox 的网络架构中,Physical Function(PF)在 switchdev 模式下充当 eSwitch manager&am…...

深入理解二叉树:遍历、存储与算法实现
在之前的博客系列中,我们系统地探讨了多种线性表数据结构,包括顺序表、栈和队列等经典结构,并通过代码实现了它们的核心功能。从今天开始,我们将开启一个全新的数据结构篇章——树结构。与之前讨论的线性结构不同,树形…...
Python3 简易DNS服务器实现
使用Python3开发一个简单的DNS服务器,支持配置资源记录(RR),并能通过dig命令进行查询。 让自己理解DNS原理 实现方案 我们将使用socketserver和dnslib库来构建这个DNS服务器。dnslib库能帮助我们处理DNS协议的复杂细节。 1. 安装依赖 首先确保安装了d…...

【Win32 API】 lstrcmpA()
作用 比较两个字符字符串(比较区分大小写)。 lstrcmp 函数通过从第一个字符开始检查,若相等,则检查下一个,直到找到不相等或到达字符串的末尾。 函数 int lstrcmpA(LPCSTR lpString1, LPCSTR lpString2); 参数 lpStr…...

(C语言)超市管理系统 (正式版)(指针)(数据结构)(清屏操作)(文件读写)
目录 前言: 源代码: product.h product.c fileio.h fileio.c main.c 代码解析: 一、程序结构概述 二、product.c 函数详解 1. 初始化商品列表 Init_products 2. 添加商品 add_product 3. 显示商品 display_products 4. 修改商品 mo…...

NAT转换和ICMP
NAT nat原理示意 nat实现 ICMP ICMP支持主机或路由器: 差错或异常报告网络探寻 2类icmp报文: 差错报告报文(5种) 目的不可达源抑制--拥塞控制超时&超期--TTL超时参数问题--问题报文丢弃重定向--不应该由这个路由器转发&a…...
Executors类详解
Executors类详解 Executors 是Java中用于快速创建线程池的工具类,提供了一系列工厂方法,简化了 ThreadPoolExecutor 和 ScheduledThreadPoolExecutor 的配置。以下是其核心方法、实现原理及使用注意事项: 1. 常用线程池工厂方法 (1) newFixedThreadPool 作用:创建固定大小…...

【专利信息服务平台-注册/登录安全分析报告】
前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 暴力破解密码,造成用户信息泄露短信盗刷的安全问题,影响业务及导致用户投诉带来经济损失,尤其是后付费客户,风险巨大,造成亏损无底洞…...

BUUCTF——web刷题第一页题解
共31题,admin那题没有,因为环境问题,我做的非常卡 目录 极客大挑战 2019]Havefun [HCTF 2018]WarmU [ACTF2020 新生赛]Include [ACTF2020 新生赛]Exec [GXYCTF2019]Ping Ping Ping [SUCTF 2019]EasySQL [极客大挑战 2019]LoveSQL [极…...

哪个品牌的智能对讲机好用?推荐1款,能扛事更智能
在专业通信领域,智能对讲机早已突破传统设备的局限,成为集通信、调度、数据传输于一体的智能化终端。面对复杂多变的作业环境,用户对设备的稳定性、通信效率和智能化水平提出了更高要求。但是,市面上产品同质化严重,部…...

【Win32 API】 lstrcpyA()
作用 将字符串复制到指定的字符串缓冲区。 函数 LPSTR lstrcpyA(LPSTR lpString1, LPCSTR lpString2); 参数 lpString1 类型:LPTSTR 一个缓冲区,用于接收由 lpString2 参数指向的字符串的内容。 缓冲区必须足够大才能包含字符串,包括终止…...

Vue3——Watch侦听器
目录 手动指定监听对象 侦听ref对象 侦听ref对象中的某个属性 reactive写法 watchEffect 自动侦听 多源侦听 一次性侦听器 watch 是⼀个⽤于观察和响应Vue响应式系统中数据变化的⽅法。它允许你指定⼀个数据源(可以是 响应式引⽤、计算属性、组件的属性等…...

Go的单测gomock及覆盖率命令
安装gomock: go get github.com/golang/mock/gomockgo get github.com/golang/mock/mockgen 使用 mockgen 生成 mock 代码: 参考 mockgen -sourceservice/user.go -destinationservice/mocks/mock_user_service.go -packagemocks go test -coverprofilecoverage.out…...

Leetcode209做题笔记
力扣209 题目分析:想象一个窗口遍历着这个数组,不断扩大右边界,让r。往窗口中添加数字: 此时我们找到了这个窗口,它的和满足了大于等于target的条件,题目让我求最短的,那么我们就尝试来缩短它&…...

Suna: 开源多面手 AI 代理
GitHub:GitHub - kortix-ai/suna: Suna - Open Source Generalist AI Agent 更多AI开源软件:发现分享好用的AI工具、AI开源软件、AI模型、AI变现 - 小众AI Suna 是一个完全开源的 AI 助手,可帮助您轻松完成实际任务。通过自然对话,…...

25-05-16计算机网络学习笔记Day1
深入剖析计算机网络:今日学习笔记总结 本系列博客源自作者在大二期末复习计算机网络时所记录笔记,看的视频资料是B站湖科大教书匠的计算机网络微课堂,每篇博客结尾附书写笔记(字丑见谅哈哈) 视频链接地址 一、计算机网络基础概念 …...

12 web 自动化之基于关键字+数据驱动-反射自动化框架搭建
文章目录 一、如何实现一条用例,实现覆盖所有用例的测试1、结合数据驱动:编辑一条用例,外部导入数据实现循环测试2、用例体:实现不同用例的操作步骤对应的断言 二、实战1、项目路径总览2、common 文件夹下的代码文件3、keywords 文…...

动态IP赋能业务增效:技术解构与实战应用指南
在数字化转型加速的今天,IP地址作为网络通信的基础设施,其技术特性正深刻影响着企业业务架构的效率与安全性。动态IP(Dynamic IP)作为互联网资源分配的核心机制,早已突破传统认知中的"临时地址"定位…...

【Java ee初阶】http(1)
HTTP 全称为“超文本传输协议”,由名字可知,这是一个基于文本格式的协议,而TCP,UDP,以太网,IP...都是基于二进制格式的协议。 如何区别该协议是基于哪种格式的协议? 形如这种协议格式…...
OkHttp用法-Java调用http服务
特点:高性能,支持异步请求,连接池优化 官方文档:提供快速入门指南和高级功能(如拦截器、连接池)的详细说明,GitHub仓库包含丰富示例。 社区资源:中文教程丰富,GitHub高…...

day18-数据结构引言
一、 概述 数据结构:相互之间存在一种或多种特定关系的数据元素的集合。 1.1 特定关系: 1. 逻辑结构 2.物理结构(在内存当中的存储关系) 逻辑结构物理结构集合,所有数据在同一个集合中,关系平等顺…...

我开源了一个免费在线工具!UIED Tools
UIED Tools - 免费在线工具集合 最近更新:修改了文档说明,优化了项目结构介绍 这是设计师转开发的第一个开源项目,bug和代码规范可能有些欠缺。 这是一个功能丰富的免费在线工具集合网站,集成了多种实用工具,包括 AI …...