正定网站建设制作公司,初中生怎么提升学历,招标采购网,做网站要准备什么背景
双十一大促时#xff0c;客户客服那边反馈商品信息加载卡顿#xff0c;在不断有订单咨询时#xff0c;甚至出现了商品信息一直处于加载状态的情况#xff0c;显然#xff0c;在这种高峰期接待客户时#xff0c;是没法进行正常的接待工作的。 起初#xff0c;页面一…背景
双十一大促时客户客服那边反馈商品信息加载卡顿在不断有订单咨询时甚至出现了商品信息一直处于加载状态的情况显然在这种高峰期接待客户时是没法进行正常的接待工作的。 起初页面一直处于加载状态初步认为是后端接口返回太慢导致后经过后端日志排查发现接口返回很快根本不会造成页面一直处于加载状态甚至出现卡死的状态。后经过不断排查发现是客户端性能问题导致。
优化前
咨询订单时只咨询一条订单用时需要3秒左右当连续咨询5、6条订单时用时甚至达到了一分多钟仅仅5、6条订单竟然用时这么久那么在持续不断有订单咨询时页面就会出现一直加载甚至卡死的状态明显存在很大的性能问题。 利用performance工具可以分析主线程的Event Loop图中标出的Main就是主线程。 主线程是不断执行 Event Loop 的可以看到有很多个 Task宏任务当主线程中的任务过多时会导致主线程长时间被占用无法及时响应用户的交互操作从而影响用户体验。这种情况下页面可能会出现卡顿、延迟响应等问题。
优化后
当只咨询一条订单时用时需要1秒时间连续咨询5、6条订单用时优化到只需要3秒时间并且页面流畅对于用户体验上得到了明显的提升。
可以看出long task 减少了很多。 那么如何来优化呢请看下面的内容。
优化点
在合适的时机进行组件渲染
在排查代码的过程中发现很多本不该当前状态渲染的组件都渲染出来了显然这是不合理的。过多的组件渲染会占用大量的内存并且也会增加页面的渲染时间自然响应性能就会变得很差用户与页面的交互就会变得迟缓。 而商品信息加载部分最常见的不必要的组件渲染表现在使用Modal弹窗时我们都知道当visible为true时会弹出弹窗相应的页面内容但是当visible为false时其实是不希望渲染Modal弹窗中的内容的这会带来额外的性能开销。
下面是一些示例
- ...
- Modal
- ...
- visible{editVisible}
- ...
- ...
- /Modal
- ...{editVisible (GoodsAttributeModaleditVisible.../)}
// 把Modal弹窗作为一个单独组件提取出去并且只有当editVisible为true时才渲染组件第一段代码中使用了visible{editVisible}来控制Modal组件的显示与隐藏。当editVisible为true时Modal组件会被渲染出来否则不会被渲染。
第二段代码中使用了条件渲染的方式即通过{editVisible …}来判断是否渲染Modal组件。当editVisible为true时Modal组件会被渲染出来否则不会被渲染。
这两种方式的主要区别在于组件的渲染时机。在第一种方式中Modal组件在每次渲染时都会被创建和销毁而在第二种方式中只有在editVisible为true时才会创建和渲染Modal组件。
使用条件渲染的方式可以提高性能特别是在组件层级较深或渲染频繁的情况下。因为只有在需要显示Modal组件时才会进行渲染避免了不必要的组件创建和销毁减少了内存消耗和渲染时间。
总结起来使用条件渲染的方式可以根据需要动态地控制组件的显示与隐藏提高性能和用户体验。
使用useCallback、useMemo、React.memo提升性能
下面是一些示例 useCallback
- renderContent (content, searchKey) {
- if(content) {
- const contentWithBr content.replace(/\↵/g, br).replace(/\n/g, br)
- const regex new RegExp((${searchKey}), gi); // 创建正则表达式忽略大小写匹配
- const matches content.match(regex) || []; // 匹配结果数组
- return (
- React.Fragment
- {contentWithBr.split(br).map((text, index) (
- React.Fragment key{index}
- {index 0 br /}
- {text.split(regex).map((subText, subIndex) {
- // console.log(subText,subText,matches)
- return (
- React.Fragment key{subIndex}
- {matches.includes(subText) ? (
- span style{{ color: #FF8800 }}{subText}/span
- ) : (
- subText
- )}
- /React.Fragment
- )
- })}
- /React.Fragment
- ))}
- /React.Fragment
- )
- } else {
- return -
- }
- } const renderContent useCallback((content, searchKey) {if (content) {const contentWithBr content.replace(/\↵/g, br).replace(/\n/g, br)const regex new RegExp((${searchKey}), gi) // 创建正则表达式忽略大小写匹配const matches content.match(regex) || [] // 匹配结果数组return (React.Fragment{contentWithBr.split(br).map((text, index) (React.Fragment key{index}{index 0 br /}{text.split(regex).map((subText, subIndex) {//console.log(subText,subText,matches)return (React.Fragment key{subIndex}{matches.includes(subText) ? (span style{{ color: #FF8800 }}{subText}/span) : (subText)}/React.Fragment)})}/React.Fragment))}/React.Fragment)} else {return -}}, [])上面的代码使用了React的useCallback钩子函数来定义了一个名为renderContent的函数。useCallback的作用是用来缓存函数以便在依赖项不变的情况下避免函数的重新创建。
使用useCallback的好处是可以优化性能特别是在父组件重新渲染时避免不必要的函数重新创建。当依赖项数组为空时useCallback会在组件的初始渲染时创建函数并在后续的渲染中重复使用同一个函数。
而没有使用useCallback的情况下每次组件重新渲染时都会创建一个新的renderContent函数即使函数的实现逻辑完全相同。这可能会导致性能问题特别是在组件层级较深或渲染频繁的情况下。
因此使用useCallback可以提高组件的性能避免不必要的函数创建和内存消耗。但需要注意的是只有在确实需要缓存函数并且依赖项不变的情况下才使用useCallback否则可能会导致不必要的优化和错误。
useMemo
- const tooltip (
- div
- h2
- span className{styles.title}{title}/span
- {
- !window.isVisibleGoods (
- span
- {renderKnowledgeModal({
- label: 编辑,
- record: item,
- platGoodsId: plat_goods_id,
- classification_id: classificationId,
- })}
- a
- className{styles.delete}
- onClick{() handleDeleteKnowledage(item, classificationId)}
-
- 删除
- /a
- /span
- )
- }
- /h2
- div className{styles.img_block}{images}/div
- div
- className{classnames(styles.context, styles.tooltipsContext)}
- dangerouslySetInnerHTML{{ __html: ParseBrow.parse(context) }}
- /
- /div
- )const tooltip useMemo(() (divh2span className{styles.title}{title}/span{!isVisibleGoods (span{renderKnowledgeModal({label: 编辑,record: item,platGoodsId: plat_goods_id,classification_id: classificationId,})}aclassName{styles.delete}onClick{() handleDeleteKnowledage(item, classificationId)}删除/a/span)}/h2div className{styles.img_block}{images}/divdivclassName{classnames(styles.context, styles.tooltipsContext)}dangerouslySetInnerHTML{{ __html: ParseBrow.parse(context) }}//div),[title,renderKnowledgeModal,item,plat_goods_id,classificationId,images,context,handleDeleteKnowledage,isVisibleGoods,])在上面的代码中使用了useMemo来缓存了一个变量tooltip的计算结果。这个计算结果是一个React元素包含了一些子元素和事件处理函数等。通过将tooltip作为依赖数组的一部分当依赖数组中的值发生变化时useMemo会重新计算tooltip的值如果依赖数组中的值没有发生变化则直接返回上一次缓存的tooltip的值。
这样做的好处是当依赖数组中的值没有发生变化时可以避免重复计算tooltip的值提高组件的性能。而如果依赖数组中的值发生变化useMemo会重新计算tooltip的值确保tooltip的值是最新的。
相比之下如果不使用useMemo每次组件重新渲染时都会重新计算tooltip的值即使依赖数组中的值没有发生变化这样会造成不必要的性能损耗。
总结起来使用useMemo可以优化组件的性能避免不必要的计算。但是需要注意的是只有在计算的成本比较高时才需要使用useMemo否则可能会带来额外的开销
React.memo
- export default Itemimport { isEqual } from lodashexport default React.memo(Item, isEqual)export default Item 直接导出组件每次父组件重新渲染都会重新渲染 Item 组件 而 export default React.memo(Item, isEqual) 使用 React.memo 进行包裹并传入自定义的比较函数 isEqual只有在 props 发生变化且通过 isEqual 函数比较不相等时才会重新渲染 Item 组件。 注意自定义的比较函数 isEqual 用于比较两个 props 是否相等。如果不传入比较函数则默认使用浅比较即 Object.is来比较 props。如果传入了比较函数则会使用该函数来比较 props。
props解构变量时的默认值 在这段代码中KnowledgeTab是一个使用了React.memo进行优化的组件。React.memo是一个高阶组件用于对组件进行浅层比较以确定是否需要重新渲染组件。当组件的props没有发生变化时React.memo会返回之前渲染的结果从而避免不必要的重新渲染。
在KnowledgeTab组件中knowledge_list是一个从props中解构出来的属性。而const knowledge_list_default useMemo(() [], [])是使用useMemo钩子函数创建的一个空数组。这样做的目的是为了在组件的初始渲染时给knowledge_list一个默认值以避免在解构时出现undefined的情况。
如果直接使用knowledge_list[]来给knowledge_list赋值会破坏React.memo的优化。因为每次父组件重新渲染时knowledge_list都会被重新创建即使它的值没有发生变化。这样会导致KnowledgeTab组件的props发生变化从而触发不必要的重新渲染。
而使用useMemo创建一个空数组作为默认值可以保证在父组件重新渲染时knowledge_list_default的引用不会发生变化从而避免不必要的重新渲染。这样就能够保持React.memo的优化效果只有在knowledge_list的值真正发生变化时才会重新渲染KnowledgeTab组件。
所以总结起来就是默认值如果传给子组件父组件每一次更新都会导致子组件更新导致子组件的React.memo失效
拆分为状态自治的独立组件
当一个组件的代码变得复杂或包含大量的子组件时可以考虑将其中的一部分代码抽取为一个独立的子组件。这样做的好处是可以将复杂的逻辑拆分为多个小组件提高代码的可读性和可维护性。 同时抽取组件也可以配合使用React.memo进行优化。 下面是一个抽取独立组件的例子
import React, { memo } from react
import { Tooltip } from antd
import classNames from classnames
import Item from ./item
import styles from ../../index.lessinterface Item {name: stringid: string
}
interface CategoryProps {item: ItemactiveKey: stringonClickItem: () void
}
const Category: React.FCCategoryProps props {const { item, activeKey, onClickItem } propsconst { name, id } itemreturn (Tooltiptitle{name}placementtopRightalign{{offset: [0, 5],}}spankey{id}className{classNames(styles.tab_item, {[styles.active_item]: activeKey id,})}onClick{onClickItem}{name}/span/Tooltip)
}export default memo(Category)
文章转载自: http://www.morning.qsy38.cn.gov.cn.qsy38.cn http://www.morning.kszkm.cn.gov.cn.kszkm.cn http://www.morning.kgmkl.cn.gov.cn.kgmkl.cn http://www.morning.mgbsp.cn.gov.cn.mgbsp.cn http://www.morning.tsdjj.cn.gov.cn.tsdjj.cn http://www.morning.xdjwh.cn.gov.cn.xdjwh.cn http://www.morning.mcmpq.cn.gov.cn.mcmpq.cn http://www.morning.pwrkl.cn.gov.cn.pwrkl.cn http://www.morning.jsphr.cn.gov.cn.jsphr.cn http://www.morning.wclxm.cn.gov.cn.wclxm.cn http://www.morning.zrgsg.cn.gov.cn.zrgsg.cn http://www.morning.nqpy.cn.gov.cn.nqpy.cn http://www.morning.gqfbl.cn.gov.cn.gqfbl.cn http://www.morning.hqrkq.cn.gov.cn.hqrkq.cn http://www.morning.mm27.cn.gov.cn.mm27.cn http://www.morning.nwfpl.cn.gov.cn.nwfpl.cn http://www.morning.drywd.cn.gov.cn.drywd.cn http://www.morning.llsrg.cn.gov.cn.llsrg.cn http://www.morning.jlxqx.cn.gov.cn.jlxqx.cn http://www.morning.rbyz.cn.gov.cn.rbyz.cn http://www.morning.yrskc.cn.gov.cn.yrskc.cn http://www.morning.nfsrs.cn.gov.cn.nfsrs.cn http://www.morning.rxnxl.cn.gov.cn.rxnxl.cn http://www.morning.nsncq.cn.gov.cn.nsncq.cn http://www.morning.qdrrh.cn.gov.cn.qdrrh.cn http://www.morning.jbtlf.cn.gov.cn.jbtlf.cn http://www.morning.bpmfz.cn.gov.cn.bpmfz.cn http://www.morning.bmpjp.cn.gov.cn.bmpjp.cn http://www.morning.zpfqh.cn.gov.cn.zpfqh.cn http://www.morning.wrbf.cn.gov.cn.wrbf.cn http://www.morning.hmqjj.cn.gov.cn.hmqjj.cn http://www.morning.qxwgx.cn.gov.cn.qxwgx.cn http://www.morning.zgdnz.cn.gov.cn.zgdnz.cn http://www.morning.krkwh.cn.gov.cn.krkwh.cn http://www.morning.xlwpz.cn.gov.cn.xlwpz.cn http://www.morning.fqqcd.cn.gov.cn.fqqcd.cn http://www.morning.ghfmd.cn.gov.cn.ghfmd.cn http://www.morning.ndfwh.cn.gov.cn.ndfwh.cn http://www.morning.fthcn.cn.gov.cn.fthcn.cn http://www.morning.zwckz.cn.gov.cn.zwckz.cn http://www.morning.kcfnp.cn.gov.cn.kcfnp.cn http://www.morning.cfhwn.cn.gov.cn.cfhwn.cn http://www.morning.xqcst.cn.gov.cn.xqcst.cn http://www.morning.ysbrz.cn.gov.cn.ysbrz.cn http://www.morning.vehna.com.gov.cn.vehna.com http://www.morning.trpq.cn.gov.cn.trpq.cn http://www.morning.sfrw.cn.gov.cn.sfrw.cn http://www.morning.zczkm.cn.gov.cn.zczkm.cn http://www.morning.lnbcx.cn.gov.cn.lnbcx.cn http://www.morning.cmdfh.cn.gov.cn.cmdfh.cn http://www.morning.dqpnd.cn.gov.cn.dqpnd.cn http://www.morning.hqjtp.cn.gov.cn.hqjtp.cn http://www.morning.mmqng.cn.gov.cn.mmqng.cn http://www.morning.jfbbq.cn.gov.cn.jfbbq.cn http://www.morning.jbblf.cn.gov.cn.jbblf.cn http://www.morning.fnhxp.cn.gov.cn.fnhxp.cn http://www.morning.kycwt.cn.gov.cn.kycwt.cn http://www.morning.rkdnm.cn.gov.cn.rkdnm.cn http://www.morning.jfbpf.cn.gov.cn.jfbpf.cn http://www.morning.hympq.cn.gov.cn.hympq.cn http://www.morning.wgqtj.cn.gov.cn.wgqtj.cn http://www.morning.fbjnr.cn.gov.cn.fbjnr.cn http://www.morning.sjmxh.cn.gov.cn.sjmxh.cn http://www.morning.xlmgq.cn.gov.cn.xlmgq.cn http://www.morning.rzcfg.cn.gov.cn.rzcfg.cn http://www.morning.fcftj.cn.gov.cn.fcftj.cn http://www.morning.hsjrk.cn.gov.cn.hsjrk.cn http://www.morning.zwmjq.cn.gov.cn.zwmjq.cn http://www.morning.wxckm.cn.gov.cn.wxckm.cn http://www.morning.srckl.cn.gov.cn.srckl.cn http://www.morning.mytmn.cn.gov.cn.mytmn.cn http://www.morning.chjnb.cn.gov.cn.chjnb.cn http://www.morning.hclplus.com.gov.cn.hclplus.com http://www.morning.nfpct.cn.gov.cn.nfpct.cn http://www.morning.hsgxj.cn.gov.cn.hsgxj.cn http://www.morning.gwtbn.cn.gov.cn.gwtbn.cn http://www.morning.ydrfl.cn.gov.cn.ydrfl.cn http://www.morning.kzhgy.cn.gov.cn.kzhgy.cn http://www.morning.qggcc.cn.gov.cn.qggcc.cn http://www.morning.rykw.cn.gov.cn.rykw.cn