性能優化在社區是個熱門的話題,但是隨著設備性能和網絡速度的提升,需要做性能優化的項目可能并不是很多,所以每次做優化都是技術實踐和累積的好機會。
性能優化的方式有很多,本文將從實例出發帶你了解性能優化之預加載。
近期開發了一個移動端 H5 頁面,頁面大概如下:
加載的時序如下:
頁面開發完成后,產品在驗收環節提出了頁面加載較慢的問題。
經過簡單研究,初步梳理出了慢的幾點原因:
第一點移動端設備的情況總是比較復雜,無法改變;第二點需要服務端同學去優化;主要看第三點,具體分析后,得到了慢的原因:
對于第一點目前某些頁面對用戶信息有強依賴,所以都是等用戶信息返回后,再去加載頁面 JS,就造成了一個串行的結果。
可以通過用戶信息獲取和頁面 JS 同時進行來優化,但是這樣需要去修改對用戶信息有強依賴的頁面,影響范圍較大,暫不考慮。
故采用另外一種方式解決并行問題,預加載頁面 JS。
處理完第一點后的加載時序:
第二點就用動態加載 Echarts 組件來處理,并在第一個頁面預加載這個組件來錦上添花,減少首頁加載體積并在切換時能快速展示圖表。
最終的加載時序:
預加載的三種方式:
在開始前,我們先體驗下預加載的效果。
頁面主要加載分為三步驟:
可以看到有預加載的情況下,登錄信息請求完成后頁面就立即顯示出來了。
import 函數是 ES2020 提案新增的功能,用于支持動態加載模塊。
使用方法如下:
js復制代碼import * as mod from '/my-module.js'
import('/my-module.js').then((mod2)=> {
console.log(mod===mod2)
})
在 React 項目中會配置 lazy 和 Suspense 使用,使用方法入如下:
jsx復制代碼import { lazy } from 'react';
const MarkdownPreview=lazy(()=> import('./MarkdownPreview.js'))
function App() {
return (
<Suspense fallback="loading...">
<h2>Preview</h2>
<MarkdownPreview />
</Suspense>
)
}
lazy 會將 import 方法返回對象的 default 值作為 React 節點返回,這樣我們可以在 JSX 中直接渲染組件。同時 lazy 只有在嘗試渲染該組件的時候,才會去調用 import 方法,所以是動態加載。
接下來看下項目中的 main.js 和動態加載路由配置:
jsx復制代碼// react-router
const config=[{
path: '/home',
component: React.lazy(()=> import(
/* webpackChunkName: 'IndexHome' */
'@/pages/Home'
))
}]
// main.js 獲取完用戶信息后加載路由頁面
import React, { useState, useEffect } from 'react'
import { Outlet } from 'react-router-dom'
const LayoutPage=()=> {
const [useInfo, setUserInfo]=useState()
const hasLogin=!!userInfo
useEffect(()=> {
// ... getUserInfo
}, [])
return (
<div>
{hasLogin && <Outlet />}
</div>
)
}
export default LayoutPage
支持預加載后代碼如下:
jsx復制代碼// react-router 返回預加載函數
function lazyWithPreload(factory) {
return {
component: React.lazy(factory),
preload: factory
}
}
const config=[{
path: '/home',
...lazyWithPreload(()=> import(
/* webpackChunkName: 'IndexHome' */
'@/pages/Home'
))
}]
// main.js
import React, { useState, useEffect } from 'react'
import { Outlet, matchRoutes, useLocation } from 'react-router-dom'
const LayoutPage=()=> {
const [useInfo, setUserInfo]=useState()
const hasLogin=!!userInfo
const location=useLocation()
useEffect(()=> {
// ... getUserInfo 同時發起預加載頁面內容
const matched=matchRoutes(routes, location)
if (matched) {
const pageRoute=matched[matched.length - 1]
pageRoute.route?.preload?.()
}
}, [])
return (
<div>
{hasLogin && <Outlet />}
</div>
)
}
export default LayoutPage
可以看到代碼中提供了 lazyWithPreload 方法,這方法中返回的 preload 方法,就是可以直接執行 import 操作。
預加載的操作就在于我們把 import 方法先調用了,這樣頁面 js 的加載就和請求登錄用戶信息是并行發起的。
react-router 在 v6.4+ 版本支持了 lazy 屬性,該屬性現實了動態加載頁面,并且支持并行發起頁面需要的接口數據請求。
使用方式如下:
jsx復制代碼const router=createHashRouter(routerConfig)
function App() {
return <RouterProvider router={router} />
}
jsx復制代碼const routerConfig=[{
element: <Layout />,
children: [
{ path: '/home', lazy: ()=> import('./pages/home') }
]
}]
jsx復制代碼export async function loader({ request }) {
let data=await fetchData(request);
return json(data);
}
export function Component() {
let data=useLoaderData();
return (
<div>{data}</div>
)
}
export function ErrorBoundary() {
return 'error'
}
完成以上步驟,在訪問 /home 路徑的時候,代碼會預加載頁面 JS 和發起頁面接口請求。
可以看到在頁面顯示的同時,data 數據也已經有了。
Webpack 4.6.0+ 支持了預加載能力,一個是 prefetch,一個是 preload。
使用方式:
js復制代碼import(/* webpackPrefetch: true */ './path/to/LoginModal.js')
import(/* webpackPreload: true */ './path/to/LoginMdal.js')
webpack 預加載和路由無關聯,也就是說不管加載什么頁面的時候,這段 JS 都會預加載,這可能會出現加載資源浪費情況。
綜合上述技術方案和當前項目技術棧考慮,最終使用了第一種方案。
本文從示例出發,帶你了解了如何根據項目具體情況做對應的優化。預加載知識你可以親自去體驗下,會有更深的理解。如果你有什么想交流的,歡迎在評論區留言。
代碼體驗:codesandbox.io/s/compassio…
作者:曉得迷路了 鏈接:https://juejin.cn/post/7295252900116332584 來源:稀土掘金 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
快科技8月10日消息,按照目前華為的進度來看,純血鴻蒙正式版預計會在今年第三季度由于Mate 70首發,現在官方也是著重介紹了新系統的一個重要改進。
華為官方現在介紹了鴻蒙HarmonyOS NEXT系統“安裝預加載”特性,這可以大幅提升你打開App的速度。
據介紹,預加載支持應用在安裝狀態下,提前加載數據到本地進行緩存,提升應用頁面打開速度。
該功能無需集成SDK、不修改原有數據格式,開通服務即可使用,適用于新聞、醫療、文旅等行業布局使用。
這到底提升會有多快呢?華為官方表示,基于 HarmonyOS NEXT 系統,接入預加載的應用相較于未接入的版本,頁面打開速度提升50%以上。
之前,華為常務董事、終端BG董事長、智能汽車解決方案BU董事長余承東稱:純血鴻蒙從內到外實現全棧自研。
“鴻蒙是基于OpenHarmony打造的全場景智能操作系統,這是一個源自中國、自主可控的操作系統。” 余承東說道。
原生鴻蒙打破了移動操作系統兩極格局,實現操作系統核心技術的自主可控、安全可靠,為世界提供更優選擇。