Tại Sao Website Của Bạn Load Chậm Và Cách Khắc Phục Triệt Để
Tác giả Vang Huynh — Founder & AI Engineer, AiShops· Đã đăng: 16 tháng 5, 2026
Bạn đã từng mở một website trên điện thoại, nhìn màn hình trắng 5 giây rồi bỏ đi chưa? Khách hàng của bạn cũng làm vậy — với website của bạn.
Theo nghiên cứu của Google, 53% người dùng mobile bỏ trang nếu tải lâu hơn 3 giây. Và cứ mỗi giây delay thêm, tỷ lệ chuyển đổi giảm khoảng 7%.
Nếu website của bạn load 6 giây thay vì 1 giây — bạn đang mất gần một nửa khách hàng tiềm năng trước khi họ nhìn thấy sản phẩm đầu tiên.
Bài viết này phân tích 8 nguyên nhân phổ biến nhất khiến website chậm và cách khắc phục cụ thể — dựa trên stack công nghệ mà AiShops đang sử dụng để đạt tốc độ tải trang dưới 1 giây.
Đo Tốc Độ Website Trước Khi Làm Gì Khác
Trước khi tối ưu, hãy đo tốc độ thực tế. Hai công cụ miễn phí đáng tin cậy nhất:
GTmetrix — Waterfall chart chi tiết, thấy từng resource load mất bao lâu
Ngưỡng cần đạt để không mất khách hàng:
LCP (Largest Contentful Paint — Thời gian hiển thị nội dung chính)
✅ Tốt: dưới 2.5 giây
⚠️ Cần cải thiện: 2.5 – 4 giây
❌ Kém: trên 4 giây
FID (First Input Delay — Độ trễ khi người dùng tương tác)
✅ Tốt: dưới 100ms
⚠️ Cần cải thiện: 100 – 300ms
❌ Kém: trên 300ms
CLS (Cumulative Layout Shift — Mức độ nhảy layout)
✅ Tốt: dưới 0.1
⚠️ Cần cải thiện: 0.1 – 0.25
❌ Kém: trên 0.25
Điểm PageSpeed Mobile
✅ Tốt: trên 90
⚠️ Cần cải thiện: 50 – 90
❌ Kém: dưới 50
Đo xong rồi mới đọc tiếp — bạn sẽ biết mình đang gặp vấn đề nào trong 8 vấn đề dưới đây.
Nguyên Nhân 1 — Hosting Chậm Và Xa Người Dùng
Đây là nguyên nhân phổ biến nhất và ít người để ý nhất.
Khi người dùng ở Hà Nội truy cập website của bạn đang host trên server ở Singapore hoặc Mỹ — mỗi request phải đi một quãng đường vật lý dài. Đây gọi là latency, và nó không thể tối ưu bằng code.
Dấu hiệu nhận biết: Điểm TTFB (Time To First Byte) trên GTmetrix cao hơn 600ms.
Cách khắc phục:
Dùng CDN (Content Delivery Network) để phân phối nội dung từ server gần người dùng nhất.
AiShops dùng Vercel Edge Network — hệ thống CDN toàn cầu tự động cache và phục vụ nội dung từ datacenter gần người dùng nhất. Người dùng ở Việt Nam được phục vụ từ server khu vực Đông Nam Á, TTFB thường dưới 80ms.
Ngoài Vercel, các lựa chọn CDN khác phổ biến:
Cloudflare — Miễn phí cho plan cơ bản, phủ sóng toàn cầu
Hình ảnh thường chiếm 60–80% tổng dung lượng của một trang web thương mại điện tử. Một ảnh sản phẩm chụp bằng điện thoại có thể nặng 3–8MB — trong khi phiên bản tối ưu chỉ cần 50–150KB mà vẫn đẹp trên màn hình.
Dấu hiệu nhận biết: Trong GTmetrix, tab Waterfall hiển thị các file .jpg, .png nặng vài MB mỗi cái.
3 vấn đề hình ảnh phổ biến nhất:
Vấn đề 1 — Sai định dạng file
PNG (lossless, nặng) → Dùng cho logo, icon có nền trong suốt
JPEG (có thể nén nhiều) → Dùng cho ảnh sản phẩm, banner
WebP (modern, nhỏ hơn) → Tốt nhất cho web, nhỏ hơn JPEG 25–35%
AVIF (mới nhất) → Nhỏ nhất, nhưng chưa hỗ trợ rộng
Vấn đề 2 — Ảnh quá lớn so với kích thước hiển thị
Upload ảnh 4000×3000px để hiển thị trong thumbnail 300×300px — lãng phí 99% dung lượng.
Vấn đề 3 — Không có lazy loading
Load tất cả ảnh ngay lập tức kể cả ảnh ở cuối trang mà người dùng chưa scroll đến.
import Image from 'next/image'
// ✅ Tự động: resize, convert WebP, lazy load, responsive srcset
<Image
src="/products/ao-thun-trang.jpg"
alt="Áo thun trắng Jockey"
width={600}
height={800}
quality={80}
placeholder="blur" // Hiển thị blur trong khi load
priority={false} // lazy load (true chỉ cho ảnh above-the-fold)
/>
Kết quả: Ảnh sản phẩm từ 3.2MB giảm còn 87KB — giảm 97% dung lượng mà chất lượng hiển thị không thay đổi đáng kể.
Nguyên Nhân 3 — JavaScript Bundle Quá Nặng
Mỗi thư viện JavaScript bạn cài thêm đều làm tăng dung lượng bundle — và trình duyệt phải tải, parse, thực thi tất cả trước khi trang có thể tương tác được.
Dấu hiệu nhận biết: Điểm "Reduce unused JavaScript" trong PageSpeed Insights màu đỏ hoặc cam.
Các thủ phạm phổ biến:
moment.js → 232KB (dùng date-fns thay thế: 13KB)
lodash (full) → 531KB (chỉ import hàm cần dùng)
jQuery → 87KB (không cần thiết trong React)
icon libraries → Import cả bộ icon thay vì từng icon
Cách khắc phục với Next.js:
Next.js có automatic code splitting — mỗi route chỉ load JavaScript cần thiết cho route đó, không load toàn bộ ứng dụng.
Ngoài ra, dùng dynamic import cho các component nặng chỉ dùng khi cần:
import dynamic from 'next/dynamic'
// ❌ Trước: Load tất cả dù user không mở modal
import ProductGallery from '@/components/ProductGallery'
// ✅ Sau: Chỉ load khi user click xem ảnh
const ProductGallery = dynamic(
() => import('@/components/ProductGallery'),
{
loading: () => <div>Đang tải...</div>,
ssr: false // Không cần render trên server
}
)
Với shadcn/ui — thư viện component mà AiShops sử dụng — mỗi component được copy trực tiếp vào codebase thay vì import từ package. Kết quả: chỉ code nào dùng mới vào bundle, không có dead code.
Nguyên Nhân 4 — Không Dùng Server-Side Rendering Hoặc Static Generation
Website truyền thống (WordPress, thuần HTML/PHP) phải xử lý toàn bộ request trên server mỗi lần có người vào — tạo HTML từ database, rồi gửi về browser. Với traffic cao, server quá tải và mọi người đều chờ.
Cách khắc phục với Next.js App Router:
Next.js cung cấp 3 chiến lược rendering — chọn đúng chiến lược cho đúng loại nội dung:
// 1. Static Generation (SSG) — Tốt nhất cho trang ít thay đổi
// Được build sẵn, phục vụ từ CDN, không cần server
// Dùng cho: Trang chủ, trang About, Blog
// app/about/page.tsx — mặc định là static
export default function AboutPage() {
return <div>Giới thiệu AiShops</div>
}
// 2. Incremental Static Regeneration (ISR) — Cho trang thay đổi định kỳ
// Build sẵn nhưng tự refresh sau X giây
// Dùng cho: Trang sản phẩm, danh mục
// app/shop/page.tsx
export const revalidate = 3600 // Cập nhật mỗi 1 giờ
export default async function ShopPage() {
const products = await getProducts() // Fetch từ Supabase/Prisma
return <ProductGrid products={products} />
}
// 3. Dynamic Rendering — Cho nội dung cá nhân hóa
// Render mỗi request, không cache
// Dùng cho: Trang giỏ hàng, tài khoản, đơn hàng
// app/account/orders/page.tsx
export const dynamic = 'force-dynamic'
export default async function OrdersPage() {
const orders = await getUserOrders() // Cần auth context
return <OrderList orders={orders} />
}
AiShops dùng ISR cho trang sản phẩm — trang được build sẵn và serve từ CDN, nhưng tự động cập nhật khi có sản phẩm mới mà không cần build lại toàn bộ website.
Nguyên Nhân 5 — Database Query Chậm
Trang web có thể nhanh về frontend nhưng chậm vì database query mất 2–5 giây mỗi lần load.
Dấu hiệu nhận biết: TTFB cao (trên 1s) dù đã dùng CDN tốt — tức là server đang chờ database.
Lỗi 1 — N+1 Query Problem:
// ❌ Sai: 1 query lấy sản phẩm + N query lấy ảnh cho từng sản phẩm
const products = await prisma.product.findMany()
for (const product of products) {
product.images = await prisma.productImage.findMany({
where: { product_id: product.id }
})
}
// 100 sản phẩm = 101 queries → RẤT CHẬM
// ✅ Đúng: 1 query duy nhất với include
const products = await prisma.product.findMany({
include: {
images: true,
variants: {
include: { attributeValues: true }
}
}
})
// 100 sản phẩm = 1 query → NHANH
Lỗi 2 — Thiếu Index:
-- ❌ Query không có index: scan toàn bộ bảng
SELECT * FROM products WHERE slug = 'ao-thun-trang-jockey';
-- ✅ Thêm index vào Prisma schema:
model Product {
id String @id @default(uuid())
slug String @unique -- @unique tự tạo index
@@index([status, created_at]) -- Index kép cho filter + sort
}
Lỗi 3 — Lấy quá nhiều data không cần thiết:
// ❌ Lấy tất cả field, kể cả description dài hàng nghìn chữ
const products = await prisma.product.findMany()
// ✅ Chỉ lấy field cần cho trang listing
const products = await prisma.product.findMany({
select: {
id: true,
name: true,
slug: true,
thumbnail_url: true,
variants: {
select: { price: true },
take: 1,
orderBy: { price: 'asc' }
}
}
})
AiShops dùng Supabase với Prisma ORM — Prisma giúp tránh N+1 query thông qua include, trong khi Supabase PostgreSQL có connection pooling tự động, giữ latency database ổn định kể cả khi traffic đột biến.
Nguyên Nhân 6 — CSS Không Được Tối Ưu
CSS nặng hoặc blocking render cũng làm chậm tốc độ tải trang đáng kể.
Dấu hiệu nhận biết: "Eliminate render-blocking resources" xuất hiện trong PageSpeed Insights.
Cách khắc phục:
Tailwind CSS — thư viện styling AiShops sử dụng — giải quyết vấn đề này theo cách triệt để nhất: chỉ generate CSS cho các class thực sự được dùng trong code, loại bỏ 99% CSS không cần thiết.
// tailwind.config.js
module.exports = {
content: [
'./app/**/*.{js,ts,jsx,tsx}',
'./components/**/*.{js,ts,jsx,tsx}',
],
// Chỉ những class xuất hiện trong content mới được giữ lại
// Kết quả: CSS production bundle thường < 20KB
}
So sánh kích thước CSS thực tế:
Bootstrap (đầy đủ): ~160KB
Tailwind (development): ~3.8MB
Tailwind (production): ~8–20KB ← Sau khi purge unused classes
Nguyên Nhân 7 — Không Có Caching Strategy
Mỗi lần người dùng reload trang, browser lại tải toàn bộ JS, CSS, ảnh từ đầu — kể cả những file không hề thay đổi.
Cách khắc phục với Next.js:
Next.js tự động thêm cache headers cho static assets:
# JS/CSS files (tên file chứa hash): Cache 1 năm
Cache-Control: public, max-age=31536000, immutable
# HTML pages: Revalidate mỗi lần (không cache)
Cache-Control: no-cache, no-store, must-revalidate
Với TanStack Query (React Query) — AiShops dùng để quản lý server state:
// hooks/useProducts.ts
import { useQuery } from '@tanstack/react-query'
export function useProducts(categorySlug?: string) {
return useQuery({
queryKey: ['products', categorySlug],
queryFn: () => fetchProducts(categorySlug),
staleTime: 5 * 60 * 1000, // Data "tươi" trong 5 phút
gcTime: 30 * 60 * 1000, // Giữ cache 30 phút
// User quay lại trang shop trong 5 phút
// → Không cần fetch lại, hiển thị ngay lập tức
})
}
Nguyên Nhân 8 — Third-Party Scripts Không Kiểm Soát
Google Analytics, Facebook Pixel, Zalo widget, live chat... mỗi script thêm vào đều load thêm vài trăm KB và chiếm thêm thời gian xử lý của browser.
Dấu hiệu nhận biết: Trong GTmetrix Waterfall, thấy nhiều request đến domain lạ (connect.facebook.net, googletagmanager.com) xuất hiện ngay đầu trang.
Cách khắc phục:
Load third-party scripts sau khi trang đã hiển thị xong, không block render:
// app/layout.tsx
import Script from 'next/script'
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
{/* ✅ afterInteractive: Load sau khi trang đã interactive */}
<Script
src="https://connect.facebook.net/vi_VN/fbevents.js"
strategy="afterInteractive"
/>
{/* ✅ lazyOnload: Load khi browser rảnh */}
<Script
src="https://www.googletagmanager.com/gtag/js"
strategy="lazyOnload"
/>
{/* ❌ Tránh dùng strategy="beforeInteractive"
trừ khi thực sự cần thiết */}
</body>
</html>
)
}
Kiểm Tra Lại Sau Khi Tối Ưu
Sau khi áp dụng các giải pháp trên, đo lại bằng PageSpeed Insights và so sánh với mục tiêu:
Điểm PageSpeed Mobile: từ dưới 50 → mục tiêu trên 90
LCP: từ trên 4 giây → mục tiêu dưới 2.5 giây
TTFB: từ trên 1 giây → mục tiêu dưới 200ms
Tổng dung lượng trang: từ trên 5MB → mục tiêu dưới 1MB
Số lượng requests: từ trên 80 → mục tiêu dưới 30
Stack Công Nghệ AiShops Dùng Để Đạt Tốc Độ Dưới 1 Giây
Tổng hợp toàn bộ giải pháp kỹ thuật mà AiShops đang áp dụng:
💾 Không có cache
Giải pháp: Stale-while-revalidate — TanStack Query
📜 Third-party scripts
Giải pháp: Deferred loading — Next.js Script
🧩 Component library nặng
Giải pháp: Copy-paste, no dead code — shadcn/ui
Website demo aishops.me/vi đạt điểm PageSpeed Mobile trên 90 và tốc độ tải trang dưới 1 giây — bạn có thể tự kiểm tra tại pagespeed.web.dev.
Tổng Kết
Website chậm không phải số phận — đó là vấn đề kỹ thuật có thể giải quyết được.
8 nguyên nhân và giải pháp trong bài viết này theo thứ tự ưu tiên:
Hosting + CDN — Impact lớn nhất, fix nhanh nhất
Hình ảnh — Thường chiếm 60–80% dung lượng trang
JavaScript bundle — Quan trọng với website React/Next.js
Server rendering strategy — SSG/ISR đúng chỗ
Database query — N+1 và thiếu index là thủ phạm phổ biến
CSS — Dùng Tailwind để giải quyết tự động
Caching — Giảm tải server và tăng tốc cho user quay lại
Third-party scripts — Deferred load để không block render
Nếu bạn đang xem xét xây dựng website bán hàng và muốn tốc độ tải trang dưới 1 giây ngay từ đầu — thay vì phải tối ưu từng bước một sau này — AiShops xây sẵn tất cả những điều trên vào trong nền tảng.