吐司问卷:性能优化

强化学习智能体学习过程可视化系统设计与实现 强化学习(Reinforcement Learning)作为一种试错驱动的决策建模方法,其核心挑战在于训练动态不可见、收敛机制不透明。理解智能体(Agent)如何从随机试探逐步构建策略,依赖对学习过程(Learning Process)中状态-动作价值、梯度演化与环境反馈的连续观测。本方案通过分层信号采集(环境层/智能体层/学习层)、毫秒级低延迟可视化(如Q值热力图+动态归一化)及内存映射回溯机制,将黑箱训练转化为可监控、可定位、可干预的工程闭环。适用于算法调试、教学演示与跨任务知识迁移分析等典型场景,尤其 阅读详情

吐司问卷:性能优化

Date: March 9, 2025 10:39 PM (GMT+8)


目标

  • 缓存数据,減少计算
  • 代码分析和拆分,优化首页代码体积

**注意事项:**优化要根据实际情况,不要先行优化




React 优化

要点:

  • 缓存数据,减少计算

useState 传入函数

要点:

  • useState 传入普通变量,每次组件更新都会执行
  • useState 传入函数,只在组件渲染时执行一次
  • 适合数据结构复杂、计算成本高的场景,

Case: useState 传入普通变量,每次组件更新都会执行

2025-03-09 23.29.35.gif

import React, { FC, useState } from 'react'

const Demo: FC = () => {
	console.log('Render');
	const [arr, setArr] = useState(['A', 'A', 'A'])
	const handleClick = () => {
		setArr(arr => [...arr, 'd'])
	}
	return (
		<div>
			<div>{arr}</div>
			<button onClick={handleClick}>add</button>
		</div>
	)
}

export default Demo

Case: useState 传入函数,只在组件渲染时执行一次

2025-03-09 23.38.10.gif

import React, { FC, useState } from 'react'

const genArr = () => {
	console.log('genArr...');
	const arr = Array(3).fill('A')
	return arr
}

const Demo: FC = () => {
	console.log('Render');
	const [arr, setArr] = useState(genArr)
	const handleClick = () => {
		setArr(arr => [...arr, 'd'])
	}
	return (
		<div>
			<div>{arr}</div>
			<button onClick={handleClick}>add</button>
		</div>
	)
}

export default Demo

理解:genArr 只在组件渲染时执行一次



useMemo

要点:

  • 函数组件,每次 state 更新都会重新执行函数
  • useMemo 可以缓存数据,不用每次执行函数都重新生成
  • 可用于计算量较大的场景,缓存提高性能

useMemo使用场景:

  • 依赖项不经常变化
  • 缓存的元素创建成本较高

Case: 二维码生成

image.png

比如生成二维码,依赖项为 id 和 isPublished,二维码的创建成本一般较高,就可以采用 useMemo

import React, { FC, useRef, useMemo } from 'react'
import {
  Space,
  Button,
  Typography,
  Input,
  InputRef,
  message,
  Popover,
} from 'antd'
import styles from './StatHeader.module.scss'
import { CopyOutlined, LeftOutlined, QrcodeOutlined } from '@ant-design/icons'
import useGetPageInfo from '../../../hooks/useGetPageInfo'
import { useNavigate, useParams } from 'react-router-dom'
import { QRCodeSVG } from 'qrcode.react'

const { Title } = Typography
const StatHeader: FC = () => {
  const { id } = useParams()
  const { title } = useGetPageInfo()
  const nav = useNavigate()
  const { isPublished } = useGetPageInfo()
  const urlInputRef = useRef<InputRef>(null)
  function copy() {
    const input = urlInputRef.current
    if (!input) return
    input.select()
    document.execCommand('copy')
    message.success('复制成功')
  }
  const LinkAndQRCodeElem = useMemo(() => {
    if (!isPublished) return null
    const url = `http://localhost:3000/questionnaire/${id}`
    const QRCodeElem = (
      <div style={{ textAlign: 'center' }}>
        <QRCodeSVG value={url} size={150} />
      </div>
    )
    return (
      <Space>
        <Input value={url} style={{ width: '300px' }} ref={urlInputRef} />
        <Button icon={<CopyOutlined />} onClick={copy}></Button>
        <Popover content={QRCodeElem}>
          <Button icon={<QrcodeOutlined />}></Button>
        </Popover>
      </Space>
    )
  }, [id, isPublished])

  return (
    <div className={styles['header-wrapper']}>
      <div className={styles.header}>
        <div className={styles.left}>
          <Space align="center">
            <Button type="link" icon={<LeftOutlined />} onClick={() => nav(-1)}>
              返回
            </Button>
            <Title>{title}</Title>
          </Space>
        </div>
        <div className={styles.main}>{LinkAndQRCodeElem}</div>
        <div className={styles.right}>
          <Button
            type="primary"
            onClick={() => {
              nav(`/question/edit/${id}`)
            }}
          >
            编辑问卷
          </Button>
        </div>
      </div>
    </div>
  )
}
export default StatHeader



useCallback

要点:

  • 和 useMemo 作用一样
  • 专门用于缓存函数

Case:

2025-02-14 23.29.16.gif

import React, { useState, memo, useMemo, useCallback } from 'react'

// 1-memo包裹子组件
const Child = memo(({ userInfo, onChange }) => {
  console.log('Child render')
  return (
    <div>
      <p>Name is {userInfo.name}</p>
      <input type="text" onChange={onChange} />
    </div>
  )
})

function App() {
  const [count, setCount] = useState(0)
  const [name, setName] = useState('Nathan')
  // 2-useMemo缓存数据
  const userInfo = useMemo(() => {
    return { name, age: 20 }
  }, [name])
  const handleChange = useCallback(e => {
    console.log('onChange', e.target.value)
  }, [])
  console.log('Parent render')
  return (
    <div>
      <p>Count is {count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
      <Child userInfo={userInfo} onChange={handleChange} />
    </div>
  )
}

export default App

参考:React Hooks



React.memo

  • state 变化,组件会更新
  • 同时,子组件默认会“无脑”更新,无论 props 是否变化
  • 根要控制子组件更新,需使用 React.memo



优化代码体积

代码分析

要点:

  • 通过分析工具,分析各包的大小,并通过 Serve 查看对应包体积

笔记:

Source map explorer,分析 JavaScript 包。这有助于了解代码膨胀的来源。

npm install --save source-map-explorer

然后在 package.json 中,添加以下行到 scripts :

   "scripts": {
+    "analyze": "source-map-explorer 'build/static/js/*.js'",
     "start": "react-scripts start",
     "build": "react-scripts build",
     "test": "react-scripts test",

构建包 & 分析包:

npm run build
npm run analyze

参考文档:

https://create-react-app.dev/docs/analyzing-the-bundle-size


**打包资源图:**根据图分析如何进行拆包处理

image.png

分包前 main 包大小为 1.3MB

serve -s build

image.png



路由懒加载

目标:

  • 首页加载速度提升

分析:

资源图分析:@dnd-kit,recharts 资源体积占比很高,它仅用于统计分析页、编辑器。

而首页用不到这些功能,因此可以将它们拆分出去。

image.png

解决方案:

我们可以通过路由懒加载,拆分 bundle,以此优化首页体积。

index.tsx

// import Edit from '../pages/question/Edit'
// import Stat from '../pages/question/Stat'

const Edit = lazy(
  () => import(/* webpackChunkName: "editPage" */ '../pages/question/Edit')
)
const Stat = lazy(
  () => import(/* webpackChunkName: "statPage" */ '../pages/question/Stat')
)

进行打包与分析:

可以看到 main 包从 1.7 MB 降低到了 1.2 MB

npm run build

image.png

image.png



分包加载

目标:

  • 拆分 antd 和 react-dom

image.png


分析:

在资源图中,antd 和 react-dom 占比很高,我们考虑将其拆分出去。

思考:

  • andt、react-dom 包版本不常更新,可以拆分,并通过浏览器进行缓存

比如浏览器第一次请求服务器资源,会返回 src、antd、react-dom 等包。

浏览器将 antd、react-dom 缓存。之后,浏览器再次请求,服务端就不用发送这些包了。

image.png

  • 在生产环境应用以上规则

分包方式:

将包分成 src、antd、react-dom 以及第三包 这四种包

craco.config

webpack: {
  configure: webpackConfig => {
    // 生产环境:抽离公共代码
    if (webpackConfig.mode === 'production') {
      if (webpackConfig.optimization === null) {
        webpackConfig.optimization = {}
      }
      webpackConfig.optimization.splitChunks = {
        chunks: 'all',
        // 采用缓存,提高打包速度
        cacheGroups: {
          antd: {
            name: 'antdchunk',
            test: /antd/,
            priority: 100,
          },
          reactDom: {
            name: 'reactDom-chunk',
            test: /react-dom/,
            priority: 99,
          },
          // 第三方插件
          vendors: {
            name: 'vendors-chunk',
            test: /node_modules/,
            priority: 98,
          },
        },
      }
    }
    return webpackConfig
  },
},

npm run build 后可见分析(以下是压缩后):

File sizes after gzip:

  343.21 kB (+18.63 kB)  build/static/js/vendors-chunk.7bb93744.js
  138.79 kB (+400 B)     build/static/js/antdchunk.44c16e36.js
  41.45 kB               build/static/js/reactDom-chunk.1439cf47.js
  9.59 kB (+554 B)       build/static/js/main.29ab4e1f.js
  3.88 kB (+10 B)        build/static/js/editPage.b9332f3b.chunk.js
  3.36 kB (+38 B)        build/static/js/766.9f144573.chunk.js
  2.44 kB (-7 B)         build/static/js/statPage.85a628ec.chunk.js
  955 B                  build/static/css/editPage.2fabb9d5.chunk.css
  820 B                  build/static/css/main.d0183c63.css
  633 B (+34 B)          build/static/css/statPage.82d41fdf.chunk.css

分包后可见 main包为 26.3 KB :

image.png

资源图如下所示:

image.png

参考:

  • https://www.webpackjs.com/plugins/split-chunks-plugin/#root


CSS拆分

Craco 会自动根据路由来拆分css,所以以上路由懒加载实现后,Craco 已经拆分出 editPage、statPage 的 css 文件,如下所示:

File sizes after gzip:

  343.21 kB (+18.63 kB)  build/static/js/vendors-chunk.7bb93744.js
  138.79 kB (+400 B)     build/static/js/antdchunk.44c16e36.js
  41.45 kB               build/static/js/reactDom-chunk.1439cf47.js
  9.59 kB (+554 B)       build/static/js/main.29ab4e1f.js
  3.88 kB (+10 B)        build/static/js/editPage.b9332f3b.chunk.js
  3.36 kB (+38 B)        build/static/js/766.9f144573.chunk.js
  2.44 kB (-7 B)         build/static/js/statPage.85a628ec.chunk.js
  955 B                  build/static/css/editPage.2fabb9d5.chunk.css
  820 B                  build/static/css/main.d0183c63.css
  633 B (+34 B)          build/static/css/statPage.82d41fdf.chunk.css
webpack 多应用处理方案 webpack多页面处理方案说明先展示一下打包完毕的内容生产环境开发环境执行命令验证规则方案说明强调:这只是一种处理方式,多多自行研究与分享! 方案说明 前端工程多数是使用webpack来开发,那么问题来了,是一个前端工程就得搭建一个webpack项目吗?我是觉得没这必要,因为很多是固定不变的,如编译… 只是前端工程对应的业务不相同而已! 先展示一下打包完毕的内容 由上图可见,页面工程按模块区分... 阅读详情

相关推荐

小红书UID泄露风险揭秘:如何防止你的手机号被社工库关联(附防护指南)

本文揭示了小红书UID泄露的严重风险,详细解析了UID与手机号关联后被社工库利用的完整链条。通过分析黑产的数据整合技术,提供从基础到进阶的防护策略,包括密码管理、账号隔离和应急响应措施,帮助用户有效防范个人信息泄露风险。

ol789012345的博客 1515

Ant design pro部署到nginx

打包在ant design pro工程目录下,使用一条命令就可以打包:cnpm run build 返回结果> ant-design-pro@1.0.0 build D:\antd_prj > umi build Build completed in 58.478s DONE Compiled successfully in 58489ms ...

899

0/1背包问题:从暴力递归到动态规划详解

题目: 有一组数量为 n 个物品,每个物品都有重量w 和价值v 给定一个背包bag,背包装的物品不能超过背包最大载重容量返回背包bag 能装下的最大价值1. 物品的重量和价值:2. 背包的容量:暴力解法的核心是递归,通过逐一决策每个物品是否放入背包,最终找到最优解。状态定义:递归逻辑:递归终止条件: 动态规划解法 递归的暴力解法有重复子问题,导致了大量的重复计算。为了解决这个问题,我们可以使用动态规划来优化。状态定义:状态转移:边界条件: 测试方法 示例解析 假设:我们希望找到在容量为

Mr.Ayao's blog 2067

打包react项目

打包react项目 jim@MacBookPro ⮀ ~/Desktop/my-app ⮀ npm run build > my-app@0.1.0 build /Users/jim/Desktop/my-app > react-scripts build Creating an optimized production build... File sizes after gzi...

m0_37468171的博客 452

电源芯片TPS54560典型应用电路及设计详解

TPS54560 是一款配有集成型高侧 MOSFET 的 60V、5A DC-DC转换器,输入电压范围7-60V,输出电压可通过外部反馈电阻设置成略低于输入电压的任意值。**所以,**R5=31.25KΩ、R6:10KΩ(常用值)时,即可设置输出电压为 3.3V。**所以,**R5=140KΩ、R6:10KΩ(常用值)时,即可设置输出电压为12V。设计 TPS54560 的输出电压时,主要通过外部反馈电阻网络来设置输出电压。因此,输出 3.3V ,输入电压24V时推荐的电感值为 8µH 至 10µH。

weixin_42306872的博客 1万+

【人工智能论文发表】基于医学病例文本和多模态大模型的医疗影像分割方法研究

摘要:本研究提出MMS-Former,一种基于级联多模态Transformer的文本引导医学图像分割框架。该模型创新性地将临床文本信息深度融入图像分割全过程,通过SwinUNETR提取视觉特征,ClinicalBERT编码病历文本,并在解码器的每个上采样阶段通过交叉注意力模块实现多级文本特征融合。实验表明,相比纯视觉模型,MMS-Former在Dice系数和IoU指标上分别提升3%以上,在处理边界模糊目标时表现尤为突出。模型还设计了结合Dice损失和图文对比损失的复合目标函数,确保分割精度与语义对齐。代码实

u012133341的博客 141

react-create-app项目解析一 build.js

react-create-app项目解析一 build.js

qq_33715850的博客 1842

LeetCode 热题 100 回顾

力扣最受刷题发烧友欢迎的 100 道题 LeetCode 热题 100 : 题目回顾、解题思路、复杂度分析、代码实现、验证算法

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 9万+

webpack plugin 透过现象看本质

这是使用 vue-cli 编译过后的输出显示 是不是看起来不是很对你的胃口,是不是想改改样式看起来好看点,是不是想输出的内容丰富点,比如编译后的文件详情… 1改样式: 那么问题来了,如何找到这是在什么地方输出的,以及如何修改它: ...

qq_37653449的博客 1110

Sparse-ICP—(4) 加权稀疏迭代最近点算法(matlab版)

本文介绍了加权稀疏迭代最近点算法的实现。

点云侠的博客 643

9、傅里叶变换:连续时间与离散时间信号分析的核心工具

本文深入探讨了傅里叶变换在连续时间和离散时间信号分析中的核心作用,详细介绍了连续时间傅里叶变换(CTFT)和离散时间傅里叶变换(DTFT)的定义、性质及其应用。文章涵盖了傅里叶级数到傅里叶变换的推导过程、常见变换对、系统分析中的关键性质,并讨论了采样后频谱的周期延拓与混叠问题。此外,还展示了傅里叶变换在滤波器设计、通信系统调制解调等实际场景中的应用,最后展望了其在图像处理、生物医学等领域的广阔前景。

jump7的博客 68

Tus系统:项目总结

这是一个全栈低代码项目,主要业务是问卷调查与统计,分成B端和C端: B端用于管理、编辑、统计问卷,C端用于用户填写问卷。 项目的技术栈有: 前端:React + Next 后端:Nest + MongoDB 测试:Jest + Storybook

CaptainDrake的博客 1045

[Python图像处理] 十.形态学之图像顶帽运算和黑帽运算

数学形态学(Mathematical morphology)是一门建立在格论和拓扑学基础之上的图像分析学科,是数学形态学图像处理的基本理论。其基本的运算包括:腐蚀和膨胀、开运算和闭运算、骨架抽取、极限腐蚀、击中击不中变换、形态学梯度、Top-hat变换、颗粒分析、流域变换等。本篇文章主要讲解Python调用OpenCV实现图像形态学转化,包括图像顶帽运算和图像黑帽运算,基础性知识希望对您有所帮助。

杨秀璋的专栏 1万+

UmiJS可插拔的企业级 react 应用框架,配合ant-design-pro使用

入门非常简单 # 安装 $ yarn global add umi # 或者 npm install -g umi # 新建应用 $ mkdir myapp && cd myapp # 新建页面 $ umi generate page index # 本地开发 $ umi dev # 构建上线 $ umi build 介绍 ...

浩秦的博客 716

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

给webpack打包添加打包时间

原因 正常情况下构建的工程,一般都会自带这些信息参数,但是遇到一个老项目,并没时间参数,在做打包优化的过程中,都看不到打包时间,所以需要自己补上 代码 打包代码的核心代码中有个stats参数,里边就有startTime,endTime 属性,我们简单加工一下 新增的打包时间代码 // 打包时间 const times = stats.endTime - stats.startTime; const minute = Math.floor(times / 1000 / 60); con

qq_36990322的博客 4407

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

gzip文件格式解析

在windows下使用UltraEdit打开后缀的.gz的文件显示的数据格式如下: 2 bytes  GZIP标志字节:0x1f, 0x8b (\037 \213)   1 byte   压缩方法: (0..7 reserved, 8 = deflate) 1 byte   标志位:             bit 0 set: 文件可能是ASCII文本文件             bi

Mrknowledge 1万+

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Gzip格式分析

GZIP文件格式简介 GZIP最早由Jean-loup Gailly和Mark Adler创建,用于UNIX系统的文件压缩。我们在Linux中经常会用到后缀为.gz的文件,它们就是GZIP格式的。现今已经成为Internet上使用非常普遍的一种数据压缩格式,或者说一种文件格式。HTTP协议上的GZIP编码是一种用来改进WEB应用程序性能的技术。大流量的WEB站点常常使用GZIP压缩技术来让用

stonesharp的专栏 3495

关于reactjs在windows环境中使用npm run build之后,打开网页显示为空白的解决方案

刚开始学react时候,跟着官网的操作:npx create-react-app my-app cd my-app npm start构建完这个初始的项目之后,发现项目是可以正常正常访问的!然后接着就是发布上线npx run build但是发现直接打开index.html界面是一片空白这个时候我们看build的过程中的信息&gt; my-app@0.1.0 build D:\Program Fil...

xzp_forever的博客 1万+

Angular vs React vs Vue vs UISYS 的搭建及发布对比(2020年最新最全)

本文讲解 在不报培训班的情况下,如何快速入门WEB开发。 这篇文章新手不要妄想一次看完,慢慢看,可以收藏起来,一天看一个,然后实战一个。 一、难点 WEB前端开发,新手最蛋痛的莫过于如何部署发布网站,全都是各种服务配置,还得学习windows server、linux等等。 更蛋痛的是学习WEB三大框架的时候还得搭建各种脚手架、编辑器、编辑器插件、破解一些问题。“满脑子都是问号和啥也不...

超级太空人的博客 1664

webpack学习之对比 umi 和 create-react-app的打包流程和优化配置

[toc] 对外配置文件对比 umi .umirc.js // ref: https://umijs.org/config/ export default { treeShaking: true, plugins: [ // ref: https://umijs.org/plugin/umi-plugin-react.html ['umi-plugin-react', { ...

weixin_33801856的博客 4484

react开发项目linux上线,使用nginx部署react项目

一、环境准备1.安装node和yarn开始部署react前需要安装node和yarn,可以参考这里安装node和yarn。2.安装nginx二、部署构建Reat项目1.下载源代码并解压wget https://github.com/mdnice/markdown-nice/archive/master.zipunzip master.zipcd markdown-nice-master/123wg...

weixin_33279929的博客 2220

dva学习笔记一:快速上手

来源:https://dvajs.com/guide/getting-started.html 一、dva简介 dva是一个轻量级的应用框架,基于redux和redux-saga,内置react-router和fetch,是一个数据流方案,可以简化开发。由蚂蚁金服团队开源提供及维护(https://dvajs.com/)。 二、安装工具 通过npm进行安装:npm install dva-...

听樱桃在哭的博客 1768

Chrome 性能优化实战指南:2026 前端页面提速与内存优化全攻略

2026年Chrome已切换为双周更新节奏,页面性能优化规则也随之迭代。本文详解Chrome性能面板高级用法、内存泄漏排查、渲染路径优化与最新API落地技巧,帮助你把页面首屏速度提升50%以上。

Frag0ut的博客 327

闪控窗性能优化与多实例资源治理【鸿蒙心迹】

本文是闪控窗系列第三篇,聚焦**多实例场景下的资源治理**。针对用户高频开关、多任务切换导致闪控窗实例越攒越多、内存与绘制开销失控的问题,给出"实例有上限、绘制会节流、销毁能统一"的完整方案:用全局单例 `FloatMgr` 统筹实例,设硬上限(建议 3 个)并淘汰最旧;用空闲实例池复用避免频繁 create/destroy;用 `Animator` 把静止态刷新压到 1fps 甚至停更;页面销毁与退后台统一 `releaseAll`,并配合 5 分钟超时回收。

wdracky的专栏 303

AI 应用开发工程师技术实践:大模型接入、通用组件封装与性能优化

本文提出AI应用从PoC到生产的核心挑战:模型调用的持续可用、可控与可优化。通过构建统一LLM网关实现多供应商路由与故障转移,封装对话、工具调用与RAG组件以解耦业务逻辑,结合前缀缓存、批处理与流式背压治理等性能优化手段,形成“接通→接稳→接快”的工程路径,最终以工程化能力决定AI应用的生产可用性。

2301_79189962的博客 578
上一篇: 吐司问卷(React低代码):用户登陆模块实现
下一篇: Tus系统:项目总结
CaptainDrake
博客等级 码龄6年 5363粉丝 187原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值