LazyLoad hiệu quả để website chạy nhanh như một cơn gió 💨

Tại sao nên đọc bài này?

  • Quy hoạch những phần có thể LazyLoad trên một website để optimize speed
  • Một cách đơn giản nhất để cải thiện loading time

Chỉ load những thứ user cần

Khi làm optimization cho frontend, trong đầu mình luôn chỉ có một câu thần chú 🪄
Only load what users want and prefetch what users will want
User không cần xem cả trái đất, vì vậy google chỉ load những mảng mà user quan tâm
Về việc tại sao nó giúp website của chúng ta chạy nhanh hơn thì đơn giản lắm:
  1. Chỉ load những thứ user cần
  1. Nghĩa là load càng ít càng tốt
  1. Càng ít, nghĩa là dung lượng file gửi xuống cho user nhỏ hơn
  1. Nghĩa là thời gian chờ network download cái file xuống cho user nhanh hơn
  1. Nghĩa là thời gian parse cái file bỏ vào JS engine nhanh hơn
  1. Website chạy nhanh hơn 💨
 
Về mặt định nghĩa thì rất dễ đúng ko nào, tuy nhiên khi làm vào dự án thực tế, mình mới thấy để cắt giảm cái phần users không cần rất dễ bị bỏ qua dẫn tới serve user với một đống code thừa mà ko sử dụng tới. VD nhé
Phần popover chỉ xuất hiện khi user hover/click
Phần popover chỉ xuất hiện khi user hover/click
Khi user ấn copy link, gọi thư viện clipboard.js để lưu link vào Clipboard
Khi user ấn copy link, gọi thư viện clipboard.js để lưu link vào Clipboard
 
Rồi những thẻ img nằm tuối dưới cuối trang nữa
notion image
Mình giám cá là 99% project đang load trực tiếp những những đoạn code đó vào bundle và ném vào mặt users

Vậy những thứ gì có thể lazyload?

notion image
Thực tế là mình có thể đẩy rất nhiều user interactive ra lazyload, nó có thể là:
  • Modal chỉ xuất hiện khi user click vào button nào đó
  • Popover/tooltip khi user hover
  • Action copy link
  • Img khi user scroll xuống dưới
 
Nếu suy nghĩ web như những layer xếp chồng lên nhau, thỉ những layer nằm trên cao nhất có thể lazyload được
notion image
 

Đối với component

1. Tách các component ở layer interact ra file riêng

// File LoginModal.tsx import { useState } from 'react'; import { Modal, Input, Button } from 'antd'; const LoginModal = () => { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); return ( <Modal> <Input placeholder="Email" value={email} onChange={e => setEmail(e.target.value)} /> <Input placeholder="Password" value={password} onChange={e => setPassword(e.target.value)} /> <Button>Login</Button> </Modal> ); } export default LoginModal;
Ở đây, mình đưa component Login ra một file riêng

2. Lazy import component

import { Suspense, useState } from "react"; const LoginModal = React.lazy(() => import('components/LoginModal')); const HomePage = () => { const [showLoginModal, setShowLoginModal] = useState(false); return ( <div> Some other stuff here {showLoginModal && <Suspense fallback={null}> <LoginModal /> </Suspense>} </div> ); }; export default HomePage;
LoginModal sẽ chỉ load khi showLoginModal = true
Xong
 

Đối với những action cần library

1. Đưa các depedencies library vào trong hàm interaction

import { Button } from "antd"; const PostItem = () => { const handleCopy = (e) =>{ import('clipboard.js').then(module => { module.default('Hello world from thanhle.blog') }).catch(error => { console.log(error); }) } return ( <div> Some other stuff here <Button onClick={handleCopy}>Copy to clipboard</Button> </div> ); }; export default PostItem;
Lazyload clipboard.js , chi khi nào user click Copy thì mới load module đó

Khi scroll

Thường dạng này chỉ cần thêm attribute loading="lazy" vào các tag img là được
<img src="https://thanhle.blog/_next/image?url=%2Fme.jpeg&w=128&q=75" loading="lazy" alt="Thanh Le" />
 

Tradeoff

Mọi quyết định đều có tradeoff, nếu áp dụng theo các phương thức trên để Lazyload, chúng ta có được
  • Giảm tối đa bundle size gửi xuống cho user
  • SEO tốt hơn
  • Liệu cắt được vài chục kB có tốt hơn? Có vài chục kB ở lượt ở mỗi trang sẽ là big problem cho điểm PageSpeed của bạn đó
Bằng cách hy sinh
  • User sẽ phải chờ một chút khi có action gì đó. Mình nghĩ cái này không phải là vấn đề lớn, hấu hết khi load các chunk này thì size rất nhỏ nên chỉ mất tầm 100ms để load
  • Nhiều code hơn, nghĩa là có khả năng nhiều bug hơn
  • Code hơi khó đọc hơn, nghĩa là hơi khó maintain hơn
 
Ngoài ra, phương án trên mình thấy chỉ nên áp dụng cho những action mà hiếm khi user dùng tới. Copy link là một ví dụ, hiếm khi mà user dùng tính năng này trên Twitter. Những action mà thường xuyên user sử dụng thì ko cần LazyLoad làm gì cả, nút Like trên facebook là một ví dụ
Do đó, việc lazy load theo user interact mình thấy chỉ phủ hợp với những trang web rất trú trọng vào SEO và đồng thời trang web cũng có nhiều interact phức tạp. CoinMarketCap.com là một ví dụ rất tốt có thể apply cách trên

Summary

Nói chung vẫn quay lại câu thần chú
🪄
Only load what users want and prefetch what users will want
Còn việc lazyLoad theo user interaction chỉ là một cách để follow câu thần chú trên. Mỗi project sẽ có những nhu cầu và độ phức tạp khác nhau, do đó, bạn là người tốt nhất để biết nên apply cách nào để optimize webiste

Loading Comments...

Follow me @thanhledev

Xin lỗi các bạn vì thời gian qua mình không dành thời gian viết nhiều. Dạo này mình khá bận cho dự án https://getnimbus.io. Check it out 🥳