1. 程式人生 > >React專案載入效能優化

React專案載入效能優化

一、瞭解頁面載入過程

1. 開啟頁面

    這個時候頁面是完全空白的。

2. 首屏渲染

    Html 和引用的 Css 載入完畢,瀏覽器進行首次渲染,有可見的內容出現。

    我們把首次渲染需要載入的資源體積稱為“首屏體積”。

3. 首次內容渲染

    react、  react-dom、業務程式碼載入完畢,應用第一次渲染,頁面主要內容出現。

4. 可互動

    然後應用的程式碼開始執行,拉取資料、進行動態 import、響應事件等,完畢後頁面進入可互動狀態。

5. 內容載入完畢

    接下來 lazyload 的圖片等多媒體內容開始逐漸載入完畢。

6. 頁面載入完畢

    然後直到頁面的其他資源載入完畢。

接下來,我們分別討論這些步驟中,有哪些優化的點。

二、首屏渲染優化

React 專案中的 Html 都會提供一個 root 節點

<div id='root'></div>

我們可以在這個 root 節點中加點內容,使第一步開啟頁面時的空白時間儘可能減少(頁面崩潰也會顯示這些內容)。

我們可以使用 html-webpack-plugin 自動給 root 節點插入內容。

// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const fs = require('fs');

// 讀取要自動插入root節點的 html 和 css
var loading = {
    html: fs.readFileSync(path.join(__dirname, './src/components/loading/index.html')),
    css: '<style>' + fs.readFileSync(path.join(__dirname, './src/components/loading/index.css')) + '</style>'
}

module.exports = {
    ...
    plugins: [
        new HtmlWebpackPlugin({
            favicon: path.resolve(config.srcPath, 'favicon.ico'),
            inject: 'body',
            template: path.join(config.srcPath, 'index.tmpl.html'),
            loading
        }),
    ]
}

然後在模板中引用即可:

// html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <%= htmlWebpackPlugin.options.loading.css %>
</head>
<body>
    <div id="root">
        <%= htmlWebpackPlugin.options.loading.html %>
    </div>
</body>
</html>

三、首次內容渲染優化

使用 react-loadable 動態 import React 元件,讓首次載入時只加載當前路由匹配的元件。

import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Loadable from 'react-loadable'
import Loading from './components/loading'

let Home = Loadable({
    loader: () => import('@/pages/home'),
    loading: Loading
})
let User = Loadable({
    loader: () => import('@/pages/user'),
    loading: Loading
})
let Others = Loadable({
    loader: () => import('@/pages/others'),
    loading: Loading
})

export default class RootRouter extends React.Component {
    render() {
        return (
            <Router>
                <Switch>
                    <Route exact path="/" component={Home}/>
                    <Route path="/user" component={User}/>
                    <Route path="/others" component={Others}/>
                    <Route component={Home}/>
                </Switch>
            </Router>
        )
    }
}

上面程式碼在首次載入時,會先展示一個 Loading,等到頁面元件程式碼載入完畢後,便會替換掉 Loading。

四、編譯到 ES2015+

把 ES2015+ 的程式碼編譯成 ES5,體積會增大好幾倍,執行速率也會減慢。在當下2018年,大部分現代瀏覽器已經支援 ES6 語法。我們要做的,就是把程式碼編譯到 ES2015+,然後給少數的老舊瀏覽器留一份 ES5 的程式碼即可。

具體的做法就是使用 <script type="module"> 標籤。

支援這個標籤的瀏覽器必然支援 async/await, Promise, Class, 箭頭函式, Map/Set, fetch 等等。

<script type="module" src="main.js"></script>
<script type="nomodule" src="main.es5.js"></script>

現代主流瀏覽器能識別 type="module",就載入第一條 ES2015+ 的程式碼。老舊瀏覽器不能識別 type="module" 和 type="nomodule",就會載入第二條 ES5 的程式碼。

五、Placeholder

我們在載入文字、圖片的時候,經常出現“閃屏”的情況,比如文字或者圖片還沒有載入完畢,此時頁面上對應的位置還是完全空著的,然後載入完畢,內容會突然撐開頁面,導致“閃屏”的出現,造成不好的使用者體驗。

為了避免這種“閃屏”的情況,我們要做的就是提前設定佔位元素,也就是 placeholder。已經有一些現成的第三方元件可以用了。