IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 【前端项目优化】React&Vue使用异步组件+代码分包+Suspense减少首页白屏时间 -> 正文阅读

[JavaScript知识库]【前端项目优化】React&Vue使用异步组件+代码分包+Suspense减少首页白屏时间

使用异步组件+Suspense的形式来实现代码分包是前端项目优化的有效&常用手段之一。

何为代码分包?

未进行代码分包的打包文件结构:
image.png
如果项目里用了第三方库的话(echarts、elementUI…),理论上还会有一个vendor.xxx.js文件。 index.xxx.js里是我们项目打包后的主文件代码。
进行代码分包的打包文件结构:

image.png
通过上述两个图的对比,可以发现,代码分包指的是打包后的项目js文件有多个。
代码分包的直观好处就是减少项目线上环境的首页白屏时间。
首页白屏时间是衡量项目的重要指标之一。首页白屏时间越短,用户体验越好。
代码分包把那些需要异步加载的组件单独形成一个js文件,在使用这些组件时才动态引入。
在首页加载过程中只会引入主js文件,从而实现减少首页白屏时间的目的。

何为异步组件?

所谓异步组件,指的是组件内的数据需要等待服务器响应结果后才能显示在页面上。
在没有收到服务器响应的结果之前,页面不会渲染这个组件。
乍一听,这件事同步组件也可以干呀,同步组件在第一次渲染的时候因为服务器还没有返回数据,因此页面渲染是空的,等前端接收到服务器返回的数据后,可以通过重新渲染把数据填充到页面呀~
但是有追求的程序员应该发现了:用同步组件干异步组件的事,会导致页面的不必要渲染。

Vue3生成异步组件&进行代码分包

通过defineAsyncComponent加载异步配合import函数模式导入异步组件,在Template模块使用Suspense控制异步组件的显示,完成异步组件的生成后,打包时就会自动实现分包。
我们可以生成一个json文件来模拟服务器端的响应结果:

// data.json
[
    {
        "name": "苹果"
    },
    {
        "name": "菠萝"
    },
    {
        "name": "西瓜"
    },
    {
        "name": "葡萄"
    }
]

然后编写一个简易版的axios来处理响应结果:

// server.ts
type NameList = {
    name: string
}

export const axios = (url:string):Promise<NameList[]> => {
    return new Promise((resolve) => {
        let xhr: XMLHttpRequest = new XMLHttpRequest()

        xhr.open('GET', url)

        xhr.onreadystatechange = () => {
            if(xhr.readyState === 4 && xhr.status === 200){
                setTimeout(() => {
                    resolve(JSON.parse(xhr.responseText))
                }, 2000)
            }
        }

        xhr.send()
    })
}

在异步组件中发起请求:

// 子组件.vue
<template>
    <div>
       <div v-for="(item, index) in list" :key="index">
            {{item.name}}
       </div>
    </div>
</template>

<script lang='ts' setup>
import { axios } from './server'

// 这个请求在项目跑起来之后,data.json文件默认就会去项目的public文件夹下面找
const list = await axios('./data.json')
</script>
 
<style lang = "less" scoped>
    
</style>

在父组件内通过defineAsyncComponent加载异步配合import引入,再使用Suspense控制显示即可

// 父组件.vue
<template>
    <div class="content">
        <Suspense>
            <template #default>
                <A></A>
            </template>
            <template #fallback>
                <div>
                    loading
                </div>
            </template>
        </Suspense>
    </div>
</template>

<script lang='ts' setup>
import { reactive, ref, defineAsyncComponent } from 'vue'

const A = defineAsyncComponent(() => import('../../DynamicComponent/A/A.vue'))
</script>

<style lang = "less" scoped>
    
</style>

页面过了定时2秒后成功加载异步组件:

image.png
然后执行npm run build,webpack或vite等打包工具就会帮我们自动分包:

image.png

需要注意的是,对于异步组件,在相关被引用的父组件里,应该都以defineAsyncComponent的方式进行引入。不能在某些父组件里以异步的方式进行引入,另一些又以同步的方式(直接使用import)进行引入。否则打包时会出现粘包问题,即没有把异步代码进行分离。

React生成异步组件&进行代码分包

按照React官网的说法:

在你的应用中引入代码分割的最佳方式是通过动态import()语法。

使用之前:

import { add } from './math';

console.log(add(16, 26));

使用之后:

import("./math").then(math => {
  console.log(math.add(16, 26));
});

当Webpack解析到该语法时,会自动进行代码分割(代码分包)。
React使用异步组件实现代码分包的代码示例如下:
和Vue重复的data.json和server.ts就不重复写了~直接上子组件和父组件:

// 异步子组件
import React, {useEffect, useState} from 'react'
import {axios} from "./server";

type NameList = {
    name: string
}
const ChildrenComponent = () => {
    const [list, setList] = useState<NameList[]>([]);

    const getData = async () => {
        return await axios("./data.json")
    }

    useEffect(() => {
        getData().then(data => setList(data))
    }, []);

    return (
        <div>
            {list.map((item) => (
                <p>{item.name}</p>
            ))}
        </div>
    )
}

export default ChildrenComponent;
// 父组件
import React,{lazy, Suspense} from 'react'

export const FatherComponent = () => {
    const ChildrenComponent = lazy(() => import('./ChildrenComponent'));

    return (
        <div>
            <Suspense fallback={<div>Loading...</div>}>
                <ChildrenComponent />
            </Suspense>
        </div>
    )
}

在实践React异步组件时,踩得一个坑是:异步子组件的导出形式必须使用default,否则父组件使用import导入时会标红。鼠标移上去,错误提示的意思就是子组件必须用default进行导出~
后面发现官网针对这点在文章最后也做了解释:

React.lazy 目前只支持默认导出(default exports)。如果你想被引入的模块使用命名导出(named exports),你可以创建一个中间模块,来重新导出为默认模块。这能保证 tree shaking 不会出错,并且不必引入不需要的组件

// ManyComponents.js
export const MyComponent = /* ... */;
export const MyUnusedComponent = /* ... */;
// MyComponent.js
export { MyComponent as default } from "./ManyComponents.js";
// MyApp.js
import React, { lazy } from 'react';
const MyComponent = lazy(() => import("./MyComponent.js"));

总结

Vue&React使用异步组件进行代码分包总结如下:

  • 相同点
    通过上述代码示例,可以发现Vue和React在引入异步组件时,都使用了Suspense这个组件,都采用动态import的方式进行异步组件的导入。
  • 不同点
    Vue引入动态import采用的是defineAsyncComponent,而React使用的是lazy。

项目优化的手段有很多,除了异步组件,还可以通过路由懒加载的方式来进行代码分包,从而实现减少首页白屏时间的目的,感觉真不错~

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-11 16:21:48  更:2022-05-11 16:23:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 19:43:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码