JavaScript惰性加載的優(yōu)化技巧詳解
這是之前的一位朋友的酒桌之談,他之前負責的一個電商項目,剛剛開發(fā)萬,首頁加載時間特別長,體驗很差,所以就開始排查,發(fā)現(xiàn)是在首頁一次性加載所有js導致的問題,這個問題在自己學習的時候并不明顯,往往被大家稱為編程習慣,甚至有的公司大佬進行項目框架層級的硬性規(guī)定或者封裝,可以起到很好的作用,但是今天還是拿出來和大家分享一下:
場景描述
網(wǎng)站在首頁一次性加載了所有模塊的JavaScript資源,包括:
- 首屏輪播圖
- 商品推薦列表
- 用戶評論模塊
- 頁腳幫助中心
- 未可視區(qū)域的廣告和營銷組件
示例代碼
// 問題代碼示例 - 同步加載所有腳本 import Carousel from './components/Carousel'; // 首屏必要 import ProductList from './components/ProductList'; // 首屏必要 import Reviews from './components/Reviews'; // 需要滾動到中部才顯示 import Ads from './components/Ads'; // 頁尾才顯示 import HelpCenter from './components/HelpCenter'; // 頁腳折疊區(qū)域 ? function HomePage() { return ( <> <Carousel /> <ProductList /> <Reviews /> <Ads /> <HelpCenter /> </> ); }
問題
1.首屏加載時間過長
用戶需要等待所有JS下載并執(zhí)行完才能看到首屏內(nèi)容
Lighthouse評分中"First Contentful Paint"指標很差
2.帶寬浪費
加載了用戶可能永遠不會看到的資源(如未滾動的底部內(nèi)容)
3.主線程阻塞
大量JS同步執(zhí)行導致主線程長時間忙碌
用戶交互(如點擊搜索框)出現(xiàn)延遲
4.內(nèi)存占用過高
初始化了所有組件,包括那些不需要立即顯示的
排查思路
這個排查的思路很通用,大部份性能問題都可以從這里著手,如果是前端的新朋友,那么建議從開頭編寫完代碼之后,多依著下面的排查思路看看自己的代碼執(zhí)行步驟,然后思考,會有意想不到的收獲。
1.初步性能評估
打開Chrome DevTools (F12)
- 切換到 Network 面板
- 勾選 Disable cache (模擬首次訪問)
- 選擇 Fast 3G 網(wǎng)絡(luò)限速(放大問題)
錄制加載過程
- 刷新頁面開始錄制
- 觀察所有資源的加載順序和時間線
2.網(wǎng)絡(luò)面板分析
JS加載問題識別
按類型篩選 JS 資源
檢查:
- 是否首屏不需要的JS過早加載
- 是否有大體積JS阻塞渲染(紅色長條)
- JS文件是否并行加載
關(guān)鍵指標查看
- Waterfall流中查找:
* 藍色豎線(DOMContentLoaded)
* 紅色豎線(Load)
- 關(guān)注:
* 首屏渲染完成時間
* 主線程被JS執(zhí)行阻塞的時間段
3.性能面板深度分析
Performance面板錄制
- 點擊 Record 后刷新頁面
- 停止后查看時間線
關(guān)鍵區(qū)域檢查
Main 線程活動:
- 長任務(wù)(超過50ms的黃色塊)
- JS編譯與執(zhí)行(紫色部分)
Network 網(wǎng)絡(luò)請求:
JS加載與執(zhí)行的關(guān)聯(lián)關(guān)系
Timings 標記:
FP/FCP/FMP/LCP等關(guān)鍵時間點
典型問題模式識別
// 問題特征示例時間線:
[JS下載1][JS執(zhí)行1][JS下載2][JS執(zhí)行2]...
// 優(yōu)化后應(yīng)有:
[首屏JS下載][首屏渲染][惰性加載其他資源]
4.內(nèi)存面板檢查
Memory面板快照
取 Heap snapshot 比較:
- 頁面剛加載時
- 滾動到底部后
內(nèi)存問題識別
- 檢查是否過早初始化了不必要組件
- 查看保留的DOM節(jié)點數(shù)量是否異常
5.Lighthouse自動化審計
生成報告
- 切換到 Lighthouse 面板
- 勾選 Performance 選項
- 點擊 Generate report
關(guān)鍵指標關(guān)注
- Opportunities中的建議:
* "Defer offscreen images"
* "Reduce unused JavaScript"
- Diagnostics中的:
* "Avoid enormous network payloads"
* "JavaScript execution time"
6.具體問題定位步驟
確定關(guān)鍵渲染路徑
在 Performance 錄制中:
- 找到 FCP (First Contentful Paint)
- 分析之前的所有JS活動
識別非必要JS
// 在Console執(zhí)行: performance.getEntriesByType('resource') .filter(r => r.initiatorType === 'script') .sort((a,b) => a.startTime - b.startTime) .map(r => ({ name: r.name.split('/').pop(), start: r.startTime, duration: r.duration }))
加載順序可視化
使用 Network 的時序圖:
- 拖動選擇首屏時間段(0-FCP)
- 右鍵 → "Save as HAR with content"
嘗試解決
懶加載最直接的理解可以是按序加載,并不是一個很完整的操作,而是很多的細節(jié)拼湊或者是自己平常注意一種習慣吧。下面列出我自己習慣性的思路:
1. 動態(tài)導入 (Dynamic Import)
import { lazy, Suspense } from 'react'; ? const Reviews = lazy(() => import('./components/Reviews')); const Ads = lazy(() => import('./components/Ads')); const HelpCenter = lazy(() => import('./components/HelpCenter')); ? function HomePage() { return ( <> <Carousel /> <ProductList /> <Suspense fallback={<Spinner />}> {/* 當元素進入視口時加載 */} <LazyLoadComponent> <Reviews /> </LazyLoadComponent> <LazyLoadComponent> <Ads /> </LazyLoadComponent> <LazyLoadComponent> <HelpCenter /> </LazyLoadComponent> </Suspense> </> ); }
2. Intersection Observer實現(xiàn)視口觸發(fā)
// 自定義懶加載組件 const LazyLoadComponent = ({ children }) => { const ref = useRef(); const [isVisible, setIsVisible] = useState(false); ? useEffect(() => { const observer = new IntersectionObserver( ([entry]) => { if (entry.isIntersecting) { setIsVisible(true); observer.disconnect(); } }, { threshold: 0.1 } ); observer.observe(ref.current); return () => observer.disconnect(); }, []); ? return <div ref={ref}>{isVisible && children}</div>; };
3. 圖片/iframe懶加載
<!-- 使用原生loading屬性 --> <img src="product.jpg" loading="lazy" alt="Product"> ? <!-- 或使用Intersection Observer實現(xiàn) --> <div class="lazy-image" data-src="product.jpg"></div>
性能影響數(shù)據(jù)(模擬)
指標 | 非惰性加載 | 惰性加載優(yōu)化后 |
---|---|---|
首屏加載時間 | 4.2s | 1.8s |
總JS體積 | 1.8MB | 650KB(首屏) |
Lighthouse性能評分 | 48 | 82 |
首次輸入延遲(FID) | 320ms | 110ms |
這些細節(jié)往往很小,但是很多,歡迎各位小伙伴一起討論。
到此這篇關(guān)于JavaScript惰性加載的優(yōu)化技巧詳解的文章就介紹到這了,更多相關(guān)JavaScript惰性加載優(yōu)化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JS字符串和數(shù)組如何實現(xiàn)相互轉(zhuǎn)化
這篇文章主要介紹了JS字符串和數(shù)組如何實現(xiàn)相互轉(zhuǎn)化,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-07-07underscore之Collections_動力節(jié)點Java學院整理
underscore為集合類對象提供了一致的接口。集合類是指Array和Object,暫不支持Map和Set。下面通過本文給大家分享underscore之Collections的相關(guān)知識,需要的的朋友參考下吧2017-07-07JavaScript 獲取任一float型小數(shù)點后兩位的小數(shù)
這篇文章主要介紹了JavaScript如何獲取小數(shù)任一小數(shù)點后的位數(shù)的小數(shù),需要的朋友可以參考下2014-06-06