سرعت سایت به چند عامل اصلی بستگی دارد: اینکه سرور چقدر سریع اولین بایت پاسخ را می‌فرستد (TTFB)، سرور چقدر از بازدیدکننده دور است، حجم و تعداد فایل‌هایی که مرورگر باید دانلود کند (به‌خصوص تصاویر، اسکریپت‌ها و فونت‌ها)، اینکه کش در کدام لایه‌ها فعال است، و اینکه هر صفحه چند کوئری سنگین به پایگاه‌داده می‌زند. معمولاً یکی دو مورد از این‌ها بیشترِ کندی را می‌سازند و بقیه سهم کوچکی دارند.

برای تست سرعت سایت، ساده‌ترین شروع ابزار رایگان گوگل یعنی PageSpeed Insights است و بعد از آن تب Network در ابزار توسعه‌دهنده‌ی مرورگر. در این مقاله اول عامل‌ها را یکی‌یکی بررسی می‌کنیم، بعد سراغ معیارهای Core Web Vitals و روش اندازه‌گیری می‌رویم و در آخر یک چک‌لیست اولویت‌دار داریم. اگر سایت شما وردپرسی است، نکته‌های مخصوص وردپرس را هم در هر بخش گفته‌ایم.

زمان پاسخ سرور (TTFB)

TTFB یا Time To First Byte فاصله‌ی بین درخواست مرورگر و رسیدن اولین بایت پاسخ است. هر کاری که سرور قبل از فرستادن HTML انجام می‌دهد در این عدد جمع می‌شود: اجرای PHP یا هر زبان دیگر، کوئری‌های پایگاه‌داده، فراخوانی سرویس‌های بیرونی و ساختن صفحه.

راهنمای رسمی گوگل TTFB زیر ۰٫۸ ثانیه را خوب می‌داند، ولی برای یک صفحه‌ی معمولی که کش شده، چند ده تا چند صد میلی‌ثانیه دست‌یافتنی است. اگر TTFB بالاست، بهینه‌کردن تصاویر و CSS کمکی نمی‌کند؛ مشکل سمت سرور است.

دلایل رایجش: هاست اشتراکی شلوغ (سرور مجازی یا هاست اشتراکی)، نبودِ کش صفحه، نسخه‌ی قدیمی PHP یا خاموش‌بودن OPcache، کوئری‌های کند، و فراخوانی یک API بیرونی وسطِ ساختن صفحه.

محل سرور نسبت به بازدیدکننده

برای باز شدن یک صفحه چندین رفت‌وبرگشت بین مرورگر و سرور لازم است: DNS، اتصال TCP، دست‌دادن TLS و بعد خود درخواست. اگر سرور در قاره‌ای دیگر باشد، هر کدام چند ده تا صدها میلی‌ثانیه اضافه می‌کند.

قاعده‌ی ساده: سرور را نزدیک بیشترِ بازدیدکننده‌هایتان بگذارید. اگر مخاطب عمدتاً داخل ایران است، سرور داخلی معمولاً تأخیر کمتری دارد؛ اگر بین‌المللی است، دیتاسنتری نزدیک به آن‌ها انتخاب کنید. HTTP/2 یا HTTP/3 را هم روی وب‌سرور فعال کنید تا فایل‌ها موازی روی یک اتصال بیایند؛ مرورگرها این را فقط روی HTTPS پشتیبانی می‌کنند (SSL رایگان با Let's Encrypt).

تصاویر: بزرگ‌ترین بخش حجم صفحه

در بیشتر سایت‌ها تصاویر سنگین‌ترین بخش صفحه‌اند. سه اشتباه رایج: فرمت قدیمی (JPEG و PNG، در حالی که WebP یا AVIF با کیفیت ظاهری یکسان معمولاً بسیار سبک‌ترند و همه‌ی مرورگرهای امروزی پشتیبانی‌شان می‌کنند)، ابعاد اشتباه (عکس ۴۰۰۰ پیکسلی برای کادر ۸۰۰ پیکسلی) و دانلود همه‌ی تصاویر از همان اول، حتی آن‌هایی که پایین صفحه‌اند. راه‌حل در HTML ساده است:

html
<img
  src="/images/product-800.webp"
  srcset="/images/product-400.webp 400w, /images/product-800.webp 800w, /images/product-1600.webp 1600w"
  sizes="(max-width: 600px) 100vw, 800px"
  width="800" height="600"
  loading="lazy"
  alt="نمای جلوی محصول">

srcset و sizes به مرورگر اجازه می‌دهند کوچک‌ترین نسخه‌ی کافی را بردارد، loading="lazy" دانلود را تا نزدیک‌شدن کاربر عقب می‌اندازد و width/height جای تصویر را رزرو می‌کنند تا صفحه جابه‌جا نشود. استثنا: تصویر اصلی بالای صفحه را lazy نکنید؛ معمولاً همان LCP است و حتی می‌شود fetchpriority="high" به آن داد.

برای تبدیل دسته‌ای تصاویر روی لینوکس، ابزار cwebp از بسته‌ی webp کافی است:

bash
sudo apt install webp
for f in *.jpg; do cwebp -q 80 "$f" -o "${f%.jpg}.webp"; done

در وردپرس، افزونه‌های بهینه‌سازی تصویر این کار را خودکار می‌کنند و خود وردپرس srcset و lazy loading را پیش‌فرض اضافه می‌کند.

کش در لایه‌های مختلف

کش یعنی نتیجه‌ی کار پرهزینه را نگه داریم تا دوباره انجامش ندهیم. چند لایه دارد:

لایه چه چیزی را نگه می‌دارد اثر
کش مرورگر فایل‌های ایستا روی دستگاه کاربر بازدید دوم تقریباً بدون دانلود
CDN فایل‌های ایستا نزدیک کاربر تأخیر شبکه‌ی کمتر
کش صفحه HTML کامل صفحه روی سرور TTFB بسیار پایین
کش آبجکت نتیجه‌ی کوئری‌ها و محاسبات (مثلاً در Redis) بار کمتر روی پایگاه‌داده
OPcache کد کامپایل‌شده‌ی PHP اجرای سریع‌تر هر درخواست

برای کش مرورگر، فایل‌هایی که نامشان با هر تغییر عوض می‌شود (مثل app.3f9c2a.css) را می‌شود برای مدت طولانی کش کرد. در Nginx:

/etc/nginx/snippets/static-cache.conf
location ~* \.(css|js|webp|avif|png|jpg|svg|woff2)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

این تنظیم فقط برای فایل‌هایی امن است که نامشان نسخه‌دار است؛ وگرنه کاربران تا یک سال نسخه‌ی قدیمی را می‌بینند.

در وردپرس، یک افزونه‌ی کش صفحه احتمالاً بیشترین اثر را با کمترین زحمت دارد. در Laravel، جزئیات اینکه چه چیزی را کجا و تا کی کش کنیم در مقاله‌ی کش در Laravel آمده و Redis را هم در Redis چیست توضیح داده‌ایم.

اسکریپت‌ها و افزونه‌های زیاد

هر فایل JavaScript باید دانلود، تجزیه و اجرا شود و در این مدت ممکن است صفحه به کلیک کاربر جواب ندهد. منابع رایج: چند ابزار آمار هم‌زمان، ویجت چت و نقشه روی همه‌ی صفحات، اسلایدرهای سنگین، و در وردپرس افزونه‌هایی که اسکریپتشان را همه‌جا بار می‌کنند و قالب‌های چندمنظوره با ده‌ها قابلیت استفاده‌نشده. تعداد افزونه به‌تنهایی معیار نیست؛ یک افزونه‌ی بد از ده افزونه‌ی سبک بدتر است. ولی افزونه‌ی بی‌استفاده را حذف کنید، نه فقط غیرفعال.

برای اسکریپت‌هایی که می‌مانند، از defer استفاده کنید تا جلوی نمایش صفحه را نگیرند:

html
<script src="/js/app.js" defer></script>

فونت‌ها

فونت فارسی معمولاً چند وزن دارد و هر وزن یک فایل جداست. فقط دو یا سه وزنی را که واقعاً استفاده می‌شوند لود کنید، فرمت woff2 را به کار ببرید، font-display: swap بگذارید تا متن منتظر دانلود فونت نماند، فونت را روی همان دامنه‌ی سایت میزبانی کنید و فونت اصلی متن را با preload زودتر درخواست کنید:

html
<link rel="preload" href="/fonts/body-regular.woff2" as="font" type="font/woff2" crossorigin>

کوئری‌های پایگاه‌داده

صفحه‌ای که برای نمایش ۲۰ محصول، ۲۱ کوئری می‌زند (یکی برای لیست و یکی برای هر محصول) مثال کلاسیک مشکل N+1 است؛ با چند رکورد حس نمی‌شود و با بزرگ‌شدن داده صفحه را کند می‌کند. راه‌های اصلی:

  • ایندکس روی ستون‌های WHERE، JOIN و ORDER BY؛ با EXPLAIN ببینید کوئری از ایندکس استفاده می‌کند یا نه.
  • Eager loading در ORMها، مثلاً with() در Laravel.
  • slow query log در MySQL یا PostgreSQL تا کوئری‌های کند خودشان را نشان دهند.
  • کار سنگین در پس‌زمینه، مثل ارسال ایمیل (صف‌ها در Laravel).

در وردپرس، رکوردهای autoload زیاد در wp_options و افزونه‌های پرکوئری از دلایل رایج کندی‌اند و افزونه‌ی Query Monitor کوئری‌های هر صفحه و زمانشان را نشان می‌دهد.

Core Web Vitals به زبان ساده

گوگل سه معیار را برای سنجش تجربه‌ی واقعی کاربر تعریف کرده که در رتبه‌بندی هم اثر دارند:

معیار چه می‌سنجد آستانه‌ی خوب
LCP (Largest Contentful Paint) چه زمانی بزرگ‌ترین بخش محتوا (معمولاً تصویر یا تیتر اصلی) دیده می‌شود ۲٫۵ ثانیه یا کمتر
INP (Interaction to Next Paint) بعد از کلیک یا تایپ، صفحه چقدر سریع واکنش نشان می‌دهد ۲۰۰ میلی‌ثانیه یا کمتر
CLS (Cumulative Layout Shift) محتوا موقع لود چقدر جابه‌جا می‌شود ۰٫۱ یا کمتر

LCP بیشتر از TTFB، تصویر اصلی سنگین و فونت‌ها اثر می‌پذیرد؛ INP معمولاً قربانی JavaScript سنگین است؛ و CLS از تصاویر بدون ابعاد، بنری که دیر وارد صفحه می‌شود و عوض‌شدن فونت می‌آید.

چطور سرعت سایت را تست کنیم

PageSpeed Insights

آدرس صفحه را در PageSpeed Insights وارد کنید. گزارش دو بخش دارد که نباید با هم قاطی شوند:

  • داده‌ی واقعی کاربران (field data): از مرورگر کروم کاربران واقعی در ۲۸ روز گذشته جمع شده و فقط برای سایت‌های با بازدید کافی نمایش داده می‌شود. گوگل در رتبه‌بندی به همین نگاه می‌کند.
  • تست آزمایشگاهی (lab data): یک اجرای Lighthouse در شرایط شبیه‌سازی‌شده. نمره‌ی ۰ تا ۱۰۰ مال این بخش است و بین دو اجرا کمی نوسان دارد.

نمره‌ی ۱۰۰ هدف نیست؛ هدف سبز بودن سه معیار Core Web Vitals است. صفحه‌ی اصلی، یک صفحه‌ی محصول یا مقاله و یک دسته‌بندی را جداگانه تست کنید و نسخه‌ی موبایل را جدی‌تر بگیرید.

تب Network مرورگر

با F12 ابزار توسعه‌دهنده را باز کنید، به تب Network بروید و گزینه‌ی Disable cache را بزنید تا بازدید اول را شبیه‌سازی کنید. صفحه را دوباره بارگذاری کنید و دنبال این‌ها بگردید:

  • اولین ردیف (سند HTML): در بخش Timing، مقدار Waiting for server response همان TTFB است.
  • ستون Size: بر اساس حجم مرتب کنید تا تصاویر و اسکریپت‌های بزرگ خودشان را نشان دهند.
  • پایین پنل: تعداد کل درخواست‌ها و حجم منتقل‌شده. درخواست به دامنه‌های دیگر معمولاً اسکریپت شخص ثالث است.
  • Throttling: با سرعت کندتر (مثل Fast 4G) تجربه‌ی کاربر موبایل را ببینید.

برای اندازه‌گیری سریع TTFB از خط فرمان هم می‌شود از curl استفاده کرد:

bash
curl -o /dev/null -s -w "dns: %{time_namelookup}s\nconnect: %{time_connect}s\ntls: %{time_appconnect}s\nttfb: %{time_starttransfer}s\ntotal: %{time_total}s\n" https://example.com/

اگر چند بار اجرا کنید و ttfb منهای tls بزرگ باشد، زمان صرف ساختن صفحه روی سرور شده است.

چک‌لیست اولویت‌دار

ترتیب زیر بر اساس اثر معمول نسبت به زحمت چیده شده است. از بالا شروع کنید و بعد از هر قدم دوباره اندازه بگیرید:

  1. اندازه بگیرید و عددهای چند صفحه‌ی مهم را یادداشت کنید.
  2. TTFB: اگر بالای حدود ۰٫۸ ثانیه است، اول کش صفحه، نسخه‌ی PHP، OPcache و میزبانی.
  3. تصاویر: WebP یا AVIF، ابعاد متناسب، lazy loading برای پایین صفحه، width/height برای همه.
  4. اسکریپت‌ها و افزونه‌های اضافه: هر چیزی که نیازش را نمی‌توانید توضیح دهید حذف شود.
  5. کش مرورگر و فشرده‌سازی: Gzip یا Brotli برای فایل‌های متنی، هدر کش برای فایل‌های ایستا.
  6. فونت‌ها: وزن کمتر، woff2، font-display: swap.
  7. پایگاه‌داده: slow query log، ایندکس، رفع N+1.
  8. محل سرور: با محل بیشتر کاربران مقایسه کنید.
  9. پایش: بعد از هر افزونه یا تغییر بزرگ دوباره تست کنید.

جمع‌بندی

سرعت سایت حاصل یک عامل نیست، ولی معمولاً یکی دو عامل بیشترش را می‌سازند: سرور کند یا بدون کش، تصاویر سنگین و اسکریپت‌های اضافه. قبل از هر تغییری اندازه بگیرید، از بزرگ‌ترین گلوگاه شروع کنید و بعد از هر قدم دوباره تست کنید. در وردپرس، یک افزونه‌ی کش خوب، تصاویر بهینه و حذف افزونه‌های بی‌استفاده معمولاً بیشترین اثر را دارند. هدف هم نمره‌ی ۱۰۰ نیست؛ هدف این است که کاربر واقعی، روی گوشی و با اینترنت معمولی، صفحه را سریع ببیند و بتواند بدون مکث با آن کار کند.