JS 效能優化 Performance
Bundle splitting 綑綁分割
將程式碼分割成較小的 bundle,從而減少初始載入時間,例如:將網頁初始所需的程式碼和點擊才需要處理的程式碼分開成兩包,如此,網頁初始渲染所需的程式碼減少,載入時間減少
壓縮 Javascript
壓縮有助於減少網路傳輸檔案的時間。Gzip 和 Brotli 是最常見的 JavaScript 壓縮方法,並受到現代瀏覽器的廣泛支援。如果使用 Webpack 捆綁程式碼,則可以使用 CompressionPlugin 進行 Gzip 壓縮,或使用 BrotliWebpackPlugin 進行 Brotli 壓縮。
module.exports = {
plugins: [
//...
new CompressionPlugin(),
],
};
另外,也可以透過Minification刪除空格或不必要的程式碼如:換行、縮排或註解等,才進一步減少檔案大小。Terser 是 ES6 熱門的 JS 壓縮工具,Webpack v4 預設包含此套件工具,舊版 webpack 也可以使用 TerserWebpackPlugin
載入資源優化
加載資源的方法有下面幾種:
- 立即載入(正常方式)
- lazy(基於 route) - 當使用者移動到特定 route 或元件時載入
- lazy(基於 interaction) - 當使用者點擊 UI 時載入,例如:youtube 點擊影片才加載
- lazy(in viewport) - 當使用者滾動到元件時加載
- prefetch - 在需要之前加載,但在加載了關鍵資源後
- preload - 有一定急迫性
dynamic import 動態載入
由於不是每個功能都會使用到,在 React 專案中 便可以使用 React lazy 和 React suspense 將程式碼拆分成不同的區塊延遲載入 ,優先載入比較重要的 js, 再載入次要的 js
Lazy動態載入 js,可以將程式碼分割,需要用到時再用 import 載入Suspense延遲載入 component 會被 suspense 包覆 ,假如 component 還沒載入完成, 就能夠透過 fallback 顯示一些提示訊息,必須搭配 Lazy 使用,如果只有寫 Lazy 沒有 Suspense 的話就會報錯
import React, { lazy, Suspense } from "react";
const InputForm = lazy(() => import("../component/InputForm"));
const FormPage = () => {
return (
<Suspense fallback={<div>Loading...</div>}>
<InputForm />
</Suspense>
);
};
export default FormPage;
但 SSR 尚未支援 lazy 和 React Suspense,這時候可以使用 loadable-components函式庫
import React from "react";
import loadable from "@loadable/component";
import Send from "./icons/Send";
import Emoji from "./icons/Emoji";
const EmojiPicker = loadable(() => import("./EmojiPicker"), {
fallback: <div id="loading">Loading...</div>,
});
const ChatInput = () => {
const [pickerOpen, togglePicker] = React.useReducer((state) => !state, false);
return (
<div className="chat-input-container">
<input type="text" placeholder="Type a message..." />
<Emoji onClick={togglePicker} />
{pickerOpen && <EmojiPicker />}
<Send />
</div>
);
};
export default ChatInput;
互動載入 Import on Interaction
例如:使用者點擊 emoji 才跳出表情選單

import React, { useState, createElement } from "react";
import MessageList from "./MessageList";
import MessageInput from "./MessageInput";
import ErrorBoundary from "./ErrorBoundary";
const Channel = () => {
const [emojiPickerEl, setEmojiPickerEl] = useState(null);
const openEmojiPicker = () => {
import(/* webpackChunkName: "emoji-picker" */ "./EmojiPicker")
.then((module) => module.default)
.then((emojiPicker) => {
setEmojiPickerEl(createElement(emojiPicker));
});
};
const closeEmojiPickerHandler = () => {
setEmojiPickerEl(null);
};
return (
<ErrorBoundary>
<div>
<MessageList />
<MessageInput onClick={openEmojiPicker} />
{emojiPickerEl}
</div>
</ErrorBoundary>
);
};
Import On Visibility 視口載入
最常見的情況是有顯示圖片庫,一開始只載入需要呈現在畫面上的圖片,當使用者向下滾動時,才動態載入後面的圖片。可以使用 IntersectionObserver API 或 react-lazyload函式庫。
prefetch 預先取回
預先取回連結(Prefetch)是一項瀏覽器機制。這項機制利用瀏覽器閒置時間,預先下載取回使用者稍後可能造訪的網頁資源,瀏覽器會將這些提前下載的資源儲存在本地 cache 中,但不執行解析
<link rel="”prefetch“" />