前端性能优化(七):前沿优化解决方案

news2025/1/18 21:00:21

目录

一:拯救移动端图标 - SVG

1.1.从 PNG 到 IconFont

1.2.从 IconFont 到 SVG

二:使用 Flexbox 优化布局

三:优化资源的加载顺序

3.1.Preload

3.2.Prefetch

四:预渲染页面

五:Windowing(窗口化)提高列表性能

六:使用骨架组件减少布局移动(Layout Shift)


一:拯救移动端图标 - SVG

1.1.从 PNG 到 IconFont

IconFont 的几个常用网站:

iconfont-阿里巴巴矢量图标库、IcoFont、Font Awesome

Iconfont 相较于 PNG 的优势:

  • 多个图标使用一套字体,减少获取时的请求数量和体积

        因为网站会有很多图标,如果使用 PNG,每个图标都需要单独设计一个文件,这样浏览器就需要对每一个文件进行加载。虽然可以使用雪碧图来规避请求数量,但是这就需要关心 icon 的定位了。iconfont 就是一套字体,就只需要获取一套字体即可

  • 矢量图形,可伸缩,可以直接通过 CSS 修改样式(颜色、大小等)

        PNG 需要关注图片的宽度、比例,以避免失真、变形

Iconfont 缺陷:

  • Iconfont 很难做到多色(自定义复杂颜色)
  • 浏览器和搜索引擎很难理解这个字体图标代表什么意思

这时人们就在想有没有什么方式类似 HTML,把这个图片描述出来,这样一方面可以显示图标,另一方面还能让搜索引擎理解这个代表什么意思。这时人们就把一项老技术 svg 翻出来了

1.2.从 IconFont 到 SVG

这里在 React 中使用 svg-sprite-loader 对 svg 进行处理

首先采用 @svgr/webpack 支持 svg 作为组件引用

npm install -D @svgr/webpack

之后在 webpack.config.js 里配置即可

module.exports = smp.wrap({
  module: {
    rules: [
      {
        test: /\.svg$/,
        use: ['@svgr/webpack'],
      },
    ],
  },
})

在页面里直接当组件使用

class About extends Component {
  render() {
    return (
      <main className={this.props.classes.root}>
        <AddressCardSvg width={100} color={'#fa1010'}/>
      </main>
    )
  }
}

svg优势:

  • 保持了图片能力,支持多色彩和复杂图标的绘制
  • 独立的矢量图形,用哪个加载哪个
  • XML 语法,搜索引擎 SEO 和无障碍读屏软件读取

二:使用 Flexbox 优化布局

关于 flex 布局,更多细节请参考我的另一篇博文:

Flex—弹性布局详解_不想学习的打工人的博客

我们设置元素的 display: flex,这个元素就会变成 flex 容器

Flexbox 优势:

  • 更好性能的实现方案:使用 Flexbox 布局在 Layout 和 Paint 耗时小于其他布局方式
  • 容器可以决定子元素的几何属性:大小、顺序、对齐方式、间隔等
  • 双向(横向、纵向)布局

三:优化资源的加载顺序

使用 Preload 和 Prefetch 改变浏览器默认的资源加载优先级

3.1.Preload

提前加载较晚出现,但对当前页面非常重要的资源

对于字体而言比较特殊,需要设置 crossorigin="anonymous"

<link rel="preload" href="test.jpg" as="font" />
<link
  rel="preload"
  href="https://fonts.gstatic.com/s/longcang/v15/LYjAdGP8kkgoTec8zkRgqBgxXsWsMfnCm1_q1j3gcsptb8OMg_Z2HVZhDbPBCIyx.119.woff2"
  as="font"
  type="font/woff2"
  crossorigin="anonymous"
/>

3.2.Prefetch

提前加载后续页面或后续路由所需的资源,优先级低

<link rel="prefetch" as="style" href="product-font.css" />

总结:对于那些在当前页面使用的资源可以利用 Preload,而对一些可能在将来某些页面中使用的资源可以利用 Prefetch。从加载优先级上看,Preload 会提升请求优先级,而 Prefetch 会把资源的优先级防止最低,当浏览器空闲时采取加载

webpack 提前预加载处理,只需要加上一行注释

import(/* webpackPrefetch: true */ './path/to/LoginModal.js')
import(/* webpackPreload: true */ 'ChartingLibrary')

四:预渲染页面

预渲染页面有点类似于我们使用的服务端渲染(SSR),通过这项技术可以帮助我们在打包的时候将单页应用的页面进行提前渲染,这样可以加快用户看到首屏的时间

预渲染的作用:

  • 大型单页应用的性能瓶颈:JS 下载 + 解析 + 执行
  • SSR 主要问题:牺牲 TTFB 来补救 First Paint,相当于给后台增加了任务量。并且由于很多插件都是基于前端渲染的,即使有 Next.js等技术,SSR 实现起来还是比较复杂
  • Pre-rendering(预渲染):针对首屏优化,打包时提前渲染页面,没有服务端参与

下面以 react-snap 插件为例进行介绍

react-snap

首先,先对插件进行安装

npm install -D react-snap

然后在 package.json 中增加一条 scipts,这里可以通过 npm 一个钩子函数,在 build 完成后,自动触发 postbuild

{
  "scripts": {
    "build": "cross-env NODE_ENV=production webpack",
    "postbuild": "react-snap"
  }
}

如果使用 react 做 SSR,它会对页面渲染进行修改,通常使用 ReactDOM.render,对主节点上相关元素进行渲染,如果主节点已经有元素了,就不需要触发 ReactDOM.render

let root = document.getElementById('main')

if (root.hasChildNodes()) {
  ReactDOM.hydrate(<App />, root)
} else {
  ReactDOM.render(<App />, root)
}

最后,在 package.json 中,可以配置内联样式,避免明显的样式闪动(FOUC)

  "reactSnap": {    
    "inlineCss": true, // 内联样式,避免明显的样式闪动 
  }

五:Windowing(窗口化)提高列表性能

windowing 的作用:

  • 加载大列表、大表单的每一行严重影响性能
  • Lazy loading 仍然会让 DOM 变得过大
  • windowing 只渲染可见的行,渲染和滚动的性能都会提升

 安装:

npm i -D react-window

以一个二维列表为例,进行使用:

import { FixedSizeGrid, FixedSizeList } from 'react-window'
import model from './model'
import React from 'react'

const items = []

for (let i = 0; i < 100; i++) {
  items.push(model.map(m => <img src={m.image} alt={m.name} width={100} height={90} />))
}

const Row = ({ index, style }) => {
  let styleExt = {
    ...style,
    borderBottom: '1px solid #fff',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
  }
  return <div style={styleExt}>{items[index]}</div>
}

class ListComponent extends React.Component {
  listRef = React.createRef()

  scrollToRow = rowNum => () => {
    if (rowNum <= 0 || rowNum > items.length) return
    this.listRef.current.scrollToItem(rowNum)
  }

  render() {
    return (
      <div>
        <button onClick={this.scrollToRow(50)}>Scroll</button>
		/* 一维列表List */
        <FixedSizeList
          ref={this.listRef}
          height={360}
          width={400}
          itemSize={120}
          itemCount={items.length}
          className={this.props.className}
        >
          {Row}
        </FixedSizeList>
		/* 二维列表Grid */
        {/* <FixedSizeGrid
          columnCount={1000}
          columnWidth={100}
          height={150}
          rowCount={1000}
          rowHeight={35}
          width={300}
        >
          {Row}
        </FixedSizeGrid> */}
      </div>
    )
  }
}

export default ListComponent

六:使用骨架组件减少布局移动(Layout Shift)

当相关组件数据还没有完全加载时,如果样式没有控制好,会导致组件没有完全撑开,当样式加载好之后,组件的布局会发生变化,对周围的组件也会造成影响,这个性能消耗比较高,我们应该尽量避免

骨架组件也叫 SkeletonPlaceholder(占位符),用来占位和提升用户感知性能,可以在 Google DevTools 里键入 ctrl + shift + p,输入 Layout Shift Regions 查看是否发生布局移动
 

安装插件

npm i -D react-placeholder

使用

import ReactPlaceholder from 'react-placeholder'

class Contact extends Component {
  render() {
    const { ready } = this.state
    const imageStyle = !ready ? { display: 'none' } : {}
    let cardMedia = (
      <CardMedia
        component={'img'}
        style={imageStyle}
        className={this.props.classes.media}
        image={this.props.image}
        onLoad={this.becomeReady}
      />
    )

    return (
      <div className={this.props.classes.root}>
        <ReactPlaceholder ready={this.state.ready} customPlaceholder={<ContactPlaceholder />}>
          /* ... */
        </ReactPlaceholder>
        {!ready && cardMedia}
      </div>
    )
  }
}

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

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

相关文章

Tomcat集群应用同步 —— 源码分析

文章目录前言一、应用同步的配置与实现原理二、应用同步源码分析三、如何获取集群的节点列表四、通讯模块Tribe五、集群的Session同步六、集群的Session共享总结前言 相信大家对Tomcat的集群部署都不陌生&#xff0c;以往&#xff0c;我们手动搭建一个Tomcat的集群环境&#x…

2023年运动耳机最新排行榜公布、公认最好用的五款运动耳机推荐

建议大家不要轻易尝试那些低价运动耳机&#xff0c;因为这些耳机大多数&#xff0c;只能满足基本听个响&#xff0c;舒适度和蓝牙稳定性都有代提高。通勤使用还勉强&#xff0c;运动强度一大&#xff0c;耳机容易掉落不说&#xff0c;蓝牙连接也很容易掉线&#xff0c;体验感受…

【自学Python】Python算术运算符

Python算术运算符 Python算术运算符教程 Python 中算术运算符是对 数值类型 的 变量 进行运算的&#xff0c;比如&#xff1a;加、减、乘、除、取模、整除和乘方运算等。 Python算数运算符语法 运算符说明实例结果加12.34 43.2155.55-减43.21 - 12.3430.87*乘2 * 3.141596…

springdata个人学习笔记

​ 入门 初始化springboot 依赖引入 <!-- springdata--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId&g…

node与node-sass版本对应

node&#xff1a;14.0.0 npm install sass-loader7.3.1 node-sass4.14.1 --savenode-sass对应node https://github.com/sass/node-sass/releases node-sass 和 sass-loader 的对应关系一般的情况下4.XX.YY&#xff0c;XX就是对应Node XX 版本 参考

Java常用工具类方法(下)

8. IOUtilsIO流在我们日常工作中也用得比较多&#xff0c;尽管java已经给我们提供了丰富的API。但我们不得不每次读取文件&#xff0c;或者写入文件之后&#xff0c;写一些重复的的代码。手动在finally代码块中关闭流&#xff0c;不然可能会造成内存溢出。有个好消息是&#xf…

一文搞懂Linux 环境变量

一文搞懂Linux 环境变量1.环境变量分类2.读取环境变量3.环境变量修改在 Linux 系统中&#xff0c;环境变量是用来定义系统运行环境的一些参数&#xff0c;比如每个用户不同的主目录&#xff08;HOME&#xff09;。 1.环境变量分类 按照作用域来分&#xff0c;环境变量可以简单…

【阶段三】Python机器学习13篇:机器学习项目实战:支持向量机分类的算法原理

本篇的思维导图: 支持向量机分类的算法原理 支持向量机分类算法的基本思路 1.最大间隔 支持向量机说到底就是一种“线性分类器”,它以“间隔”作为损失的度量,目标通过不断调整多维的“直线”——超平面,使得间隔最大化。所谓“支持向量”,就是所有数据点中直接参…

Lichee_RV学习系列---移植dhrystone

系列文章目录 Lichee_RV学习系列—认识Lichee_RV、环境搭建和编译第一个程序 文章目录系列文章目录一、dhrystone简介二、dhrystone源码下载三、dhrystone移植1、移植官方源码2、移植GitHub开源代码a&#xff1a;修改Makefile文件b&#xff1a;编译3、执行dhrstone代码总结一、…

Flink源码解析一之RPC原理解析

在阅读 Flink 源码过程中,如果你见到有这种类型的代码,其实就是在发送 RPC 请求 // resourceManagerGateway 就可以理解成: 当前节点中,对于 ResourceManager 代理对象的封 装 resourceManagerGateway.requestSlot(); // 代码跳转到:resourceManager.requestSlot()…

C++20标准下的左值与右值

C20标准下的左值与右值一、什么是左值与右值二、左值引用三、右值引用四、值类别五、标准库 move 函数5.1 用 static_cast将左值转换为右值5.2 使用 std::move 将左值转换为右值一、什么是左值与右值 左值&#xff1a;左值可以出现在赋值语句的左边或者右边右值&#xff1a;右…

Java设计模式-装饰者模式Decorator

介绍 装饰者模式的核心思想是通过创建一个装饰对象&#xff08;即装饰者&#xff09;&#xff0c;动态扩展目标对象的功能&#xff0c;并且不会改变目标对象的结构&#xff0c;提供了一种比继承更灵活的替代方案。需要注意的是&#xff0c;装饰对象要与目标对象实现相同的接口&…

VisualBox解决CentOS中yum安装失败的问题

怎么说呢&#xff0c;花了一个下午一个上午的时间&#xff0c;总算把这条命令运行成功了&#xff1a; yum install wget -y 打怪兽途中遇到了几个问题&#xff0c;总结一下&#xff1a; 1.ping 啥ip都是unkown&#xff0c;还有一种情况&#xff0c;就是ping之后就一直卡在那…

C++计算机课程设计 学生成绩管理系统 研究报告

课程设计内容 2.1 学生成绩管理系统 2.1.1 内容 主菜单模块 该模块主要用来实现整个系统的流程。主界面提供用户选择并调用各个子模块。 输入模块 当初次使用系统时&#xff0c;学生信息需要从键盘逐个输入。学生信息由学生的学号、姓名、性别、高等数学、英语、计算机和平均…

Qt基于CTK Plugin Framework搭建插件框架--CTK服务工厂

一、前言 注册服务的时候能够用服务工厂来注册&#xff1b; 访问服务getServeice中的plugin参数是执行ctkPluginContext::getService(const ctkServiceReference&)的插件&#xff0c;从而工厂根据执行的不同插件名称返回不同的服务实现 服务工厂的作用 在服务中可以知道…

达摩院2023十大科技趋势发布,生成式AI将进入应用爆发期

1月11日&#xff0c;达摩院2023十大科技趋势发布&#xff0c;生成式AI、Chiplet模块化设计封装、全新云计算体系架构等技术入选。达摩院认为&#xff0c;全球科技日趋显现出交叉融合发展的新态势&#xff0c;尤其在信息与通信技术&#xff08;ICT&#xff09;领域酝酿的新裂变&…

【关于Linux中----进程间通信方式之管道】

文章目录一、什么是管道二、匿名管道三、命名管道一、什么是管道 进程间通信主要目的为以下几点 数据传输&#xff1a;一个进程需要将它的数据发送给另一个进程 资源共享&#xff1a;多个进程之间共享同样的资源。 通知事件&#xff1a;一个进程需要向另一个或一组进程发送消息…

STL forward_list 模拟实现

forward_list 概述 forward_list 是 C 11 新增的容器&#xff0c;它的实现为单链表。 forward_list 是支持从容器中的任何位置快速插入和移除元素的容器&#xff0c;不支持快速随机访问。forward_list 和 list 的主要区别在于&#xff0c;前者的迭代器属于单向的 Forward Ite…

二分法讲解

目录 一、前言 二、二分法理论 1、引导&#xff1a;猜数游戏 2、理论背景&#xff1a;非线性方程的求根问题 1&#xff09;非线性方程的近似解 2&#xff09;搜索法和二分法 3、用二分的两个条件 4、二分法复杂度 三、整数二分 1、在单调递增序列中找 x 或者 x 的后继…

使用python-pptx创建PPT演示文档功能实践

python对PPT演示文档读写&#xff0c;是通过第三方库python-pptx实现的&#xff0c;python-pptx是用于创建和更新 PowerPoint&#xff08;.pptx&#xff09;文件的 Python 库。 关于PPT演示文档与幻灯片模板的内容不是本文的重点&#xff0c;在此略过。 1. PPT基本结构在pyth…