如何使用React.lazy与Suspense实现组件延迟加载优化前端性能

前端 潘老师 1周前 (04-16) 10 ℃ (0) 扫码查看

随着前端项目不断迭代更新,代码量会持续增加,这使得项目打包后的静态资源体积越来越大。当用户打开网页时,加载时间也会随之变长,严重影响用户体验。尤其是当页面内容不加区分地全部加载,导致整个页面在loading阶段无法交互时,用户的感受会更差。

一、实际案例分析

以一个常见的页面为例,该页面由App组件构成,而App组件又包含Header、SideBar、Content和Footer这4个React组件,代码如下:

import React from 'react';
import Header from './Header';
import SideBar from './SideBar';
import Content from './Content';
import Footer from './Footer';

function App() {
    return (
        <div className="page">
            <Header />
            <SideBar />
            <Content />
            <Footer />
        </div>
    );
}

export default App;

在Fast 3G网络环境下,通过开发者工具Network可以看到,App组件的打包文件main.chunk.js大小为7.6kB,加载时间达到774ms。面对这种情况,我们思考一下,有没有办法在保证页面功能完整的前提下,尽可能缩短页面加载App组件的时间,提升初始化页面的可交互性呢?答案是通过延迟加载App组件中一些非关键的子组件,减小App组件的体积,从而实现快速打开页面的目的。

二、React.lazy与Suspense的使用方法

(一)React.lazy函数

在React中,我们通常使用ESM的import语法来引用组件,比如import OtherComponent from './OtherComponent'; 。但如果想要实现延迟加载,就需要借助React.lazy函数。使用方式如下:

const OtherComponent = React.lazy(() => import('./OtherComponent'));

React.lazy的参数是一个回调函数,在这个回调函数里调用import方法来加载组件。import执行后会返回一个Promise,当这个Promise成功resolve时,就会返回真正的React组件,即OtherComponent。通过这种方式,引入的组件只有在首次真正被渲染时才会加载,在此之前不会产生额外的请求,达到了延迟加载的效果。

(二)Suspense组件

Suspense组件是与React.lazy配合使用的。它的使用很简单,只需用它包裹通过React.lazy引入的组件即可。并且,Suspense组件提供了一个fallback属性,我们可以设置fallback={<div>Loading...</div>} ,这样在等待加载lazy组件时,就会向用户展示“Loading…”的提示,告知用户内容正在加载中。例如:

import React, { Suspense } from'react';
const OtherComponent = React.lazy(() => import('./OtherComponent'));

function MyComponent() {
    return (
        <div>
            <Suspense fallback={<div>Loading...</div>}>
                <OtherComponent />
            </Suspense>
        </div>
    );
}

三、在实际项目中的应用

(一)单页面多组件场景

回到前面提到的包含Header、SideBar、Content和Footer组件的App页面。一般来说,用户进入页面时,首先关注到的是Header和SideBar组件,Content和Footer组件相对不是关键的首屏加载内容。所以,可以对Content和Footer组件进行延迟加载,修改后的代码如下:

import React, { Suspense } from'react';
import Header from './Header';
import SideBar from './SideBar';
// content和footer部分延迟加载
const Content = React.lazy(() => import('./Content'));
const Footer = React.lazy(() => import('./Footer'));

function App() {
    return (
        <div className="page">
            <Header />
            <SideBar />
            <Suspense fallback={<div>Loading...</div>}>
                <Content />
            </Suspense>
            <Suspense fallback={<div>Loading...</div>}>
                <Footer />
            </Suspense>
        </div>
    );
}

export default App;

延迟加载后,App组件打包文件(main.chunk.js)大小变为4.5kB,耗时664ms。相比之前,资源减少了3.1kB,体积缩减了41%,耗时减少了110ms,加载速度加快了14%。由此可见,在单页面多组件的场景下,延迟加载非关键组件,能有效减少首屏加载的资源体积,提升加载速度。对于大型复杂的业务应用,尤其是组件较多且展现优先级分明的页面,这种方式能显著提前用户可交互时间点,极大地提升用户体验。

(二)项目多路由场景

再来看一个路由相关的例子。假设有一个页面,包含3个菜单,对应3个路由入口:/home对应Home组件,/business对应Business组件,/manage对应Management组件。最初的代码如下:

import React from "react";
import {
    BrowserRouter as Router,
    Switch,
    Route,
    Link
} from "react-router-dom";
import Home from './Home';
import Business from './Business';
import Management from './Management';

export default function BasicExample() {
    return (
        <Router>
            <div>
                <ul>
                    <li>
                        <Link to="/home">Home</Link>
                    </li>
                    <li>
                        <Link to="/business">Business</Link>
                    </li>
                    <li>
                        <Link to="/manage">Management</Link>
                    </li>
                </ul>
                <hr />
                <Switch>
                    <Route exact path="/home">
                        <Home />
                    </Route>
                    <Route path="/business">
                        <Business />
                    </Route>
                    <Route path="/manage">
                        <Management />
                    </Route>
                </Switch>
            </div>
        </Router>
    );
}

在Fast 3G网络下,访问Home页面时,App组件打包文件(mian.chunk.js)大小为6.8kB,加载耗时785ms。加载完成后,菜单路由之间切换没有延迟。但考虑到用户进入系统后,通常默认先进入Home页面浏览操作,甚至可能只在Home页面停留,其他页面不会访问。为了加快Home页面的访问速度,同时不影响系统全局功能,可以对Business和Management组件进行延迟加载,仅在访问对应路由时才加载这两个组件,代码修改如下:

import React, { Suspense } from "react";
import {
    BrowserRouter as Router,
    Switch,
    Route,
    Link
} from "react-router-dom";
import Home from './Home';
// 延迟加载路由下的Business和Management组件
const Business = React.lazy(() => import('./Business'));
const Management = React.lazy(() => import('./Management'));

export default function BasicExample() {
    return (
        <Router>
            <div>
                <ul>
                    <li>
                        <Link to="/home">Home</Link>
                    </li>
                    <li>
                        <Link to="/business">Business</Link>
                    </li>
                    <li>
                        <Link to="/manage">Management</Link>
                    </li>
                </ul>
                <hr />
                <Suspense fallback={<div>Loading...</div>}>
                    <Switch>
                        <Route exact path="/home">
                            <Home />
                        </Route>
                        <Route path="/business">
                            <Business />
                        </Route>
                        <Route path="/manage">
                            <Management />
                        </Route>
                    </Switch>
                </Suspense>
            </div>
        </Router>
    );
}

优化后,访问首屏Home页时,加载的main.chunk.js体积变为5.2kB,耗时703ms。与全部组件加载时相比,体积减少了1.6kB,缩减了23%,耗时减少82ms,缩短了10%。并且,当点击Business或Management菜单时,页面会出现Suspense设置的“loading…”提示,同时在Network中能看到新加载的对应chunk.js文件。由于Business和Management组件包裹在同一个Suspense内,它们共享相同的fallback提示,这样既避免了为每个组件单独设置loading状态的繁琐,又便于对全局路由入口的loading状态进行统一管理。

在实际的系统中,往往存在多个路由入口,并且不同角色会访问不同页面。例如,角色A只能访问Home和Business页面,角色B只能访问Home和Management页面。对这些页面的组件进行延迟加载后,不仅能提高两个角色访问Home页面的速度,还能避免A加载其无需访问的Management页面资源,B也无需加载Business页面资源,这种优化对页面访问速度的提升效果明显,而且实现起来相对容易。

四、总结

在前端项目开发中,随着代码量的增加,打包文件体积膨胀,用户加载页面时间变长,还可能加载一些不必要的代码资源,这都影响了用户体验。此时,可以利用code – splitting技术来优化,在React中,React.lazy函数和Suspense组件的配合就能实现这一优化。具体实现方式是,通过React.lazy接收的函数中调用import引入组件,然后用Suspense组件包裹引入的组件,并设置fallback属性展示loading状态。这种延迟加载组件的方式,无论是在单个页面还是项目路由入口,都能避免无用资源的请求,提高页面首屏资源加载速度,从而有效提升用户体验。在实际开发中,对于单页面多组件的情况,要优先加载重要组件,延迟加载次要组件;对于项目多路由的情况,优先加载首屏路由组件,延迟加载其他路由组件。


版权声明:本站文章,如无说明,均为本站原创,转载请注明文章来源。如有侵权,请联系博主删除。
本文链接:https://www.panziye.com/front/17382.html
喜欢 (0)
请潘老师喝杯Coffee吧!】
分享 (0)
用户头像
发表我的评论
取消评论
表情 贴图 签到 代码

Hi,您需要填写昵称和邮箱!

  • 昵称【必填】
  • 邮箱【必填】
  • 网址【可选】