یک بار مشتری‌ای با لحن سردرگم پرسید: چرا سایت من در PageSpeed نمره ۹۲ می‌گیرد، ولی کاربران می‌گویند وقتی روی منو یا دکمه کلیک می‌کنند، نیم‌ثانیه‌ای انگار هیچ اتفاقی نمی‌افتد؟ اول فکر کردم شکایت کاربران دقیق نیست. اما وقتی خودم در موبایل با اینترنت سلفون سایت را باز کردم، همان حس را تجربه کردم. صفحه سریع بالا آمده بود، ولی آن لحظهٔ بی‌پاسخ بین لمس و واکنش، محسوس بود. آن روز برای اولین بار TBT را جدی گرفتم — معیاری که در گزارش‌های ابزارها معمولاً در حاشیه می‌ماند ولی مستقیماً همان لحظهٔ عصبی‌کننده را می‌سنجد.

TBT یا Total Blocking Time (زمان کل مسدودسازی)، معیاری است که مدت‌زمانی را اندازه می‌گیرد که در آن، رشتهٔ اصلی اجرای مرورگر توسط جاوااسکریپت مسدود شده و نمی‌تواند به تعامل کاربر پاسخ دهد. این معیار در ابزار Lighthouse معرفی شد و اگرچه یکی از سه معیار اصلی Core Web Vitals نیست، ولی مستقیماً روی INP (Interaction to Next Paint) اثر می‌گذارد و بخش بزرگی از تجربهٔ حس‌شدهٔ کاربران را توضیح می‌دهد. مفهوم کلی Core Web Vitals و سه معیار اصلی‌اش را در Core Web Vitals چیست و چرا گوگل بر آن تأکید دارد؟ باز کرده‌ام؛ این مقاله، به این معیار مکمل می‌پردازد.

TBT چیست و چه مسئله‌ای را می‌سنجد؟

TBT یا Total Blocking Time، مجموع مدت‌زمانی است که در آن، رشتهٔ اصلی اجرای مرورگر (Main Thread) توسط یک Long Task اشغال شده و مانع پاسخ‌دهی به تعامل کاربر می‌شود. این معیار در بازهٔ بین FCP (First Contentful Paint) و TTI (Time to Interactive) اندازه‌گیری می‌شود و واحدش میلی‌ثانیه است.

تعریف دقیق‌تر: هر Taskی که بیش از ۵۰ میلی‌ثانیه طول بکشد، Long Task نامیده می‌شود. در این حالت، فرض می‌شود که اگر مرورگر در حال اجرای این Task است، نمی‌تواند به موقع به کاربر پاسخ دهد. برای TBT، از هر Long Task، فقط بخش بیش از ۵۰ میلی‌ثانیه‌اش به‌عنوان «مسدودسازی» حساب می‌شود. یعنی اگر یک Task ۱۵۰ میلی‌ثانیه طول بکشد، ۱۰۰ میلی‌ثانیه‌اش به TBT اضافه می‌شود.

آستانه‌های TBT که در ابزارها استفاده می‌شوند:

وضعیتTBTتجربهٔ کاربر
خوبزیر ۲۰۰ میلی‌ثانیهتعاملات سریع و بی‌وقفه
نیازمند بهبودبین ۲۰۰ تا ۶۰۰ میلی‌ثانیهتأخیر محسوس در تعامل
ضعیفبالای ۶۰۰ میلی‌ثانیهسایت کند و بی‌پاسخ به‌نظر می‌رسد

نکتهٔ حیاتی این است که TBT مستقل از FCP و LCP است. یعنی ممکن است سایت شما در یک ثانیه باز شود (LCP خوب) ولی چون جاوااسکریپت سنگینی در حال اجرا باشد، تا دو ثانیه بعد از باز شدن، به کلیک کاربر پاسخ ندهد. این همان تجربهٔ متناقضی است که در ابتدای مقاله گفتم.

TBT مثل صدای درونی سایت است. صفحه ممکن است سریع بالا بیاید، ولی اگر رشتهٔ اصلی مشغول باشد، کاربر حس می‌کند سایت در همان لحظه سرش شلوغ است و جوابش را نمی‌دهد.

Long Task و Main Thread: بستر ایجاد TBT

برای درک TBT، باید بفهمید رشتهٔ اصلی در مرورگر چیست و چطور کار می‌کند. Main Thread مسئول سه کار اصلی است: پردازش HTML و CSS، اجرای جاوااسکریپت، و پاسخ‌دادن به تعاملات کاربر (کلیک، تایپ، اسکرول). همهٔ این‌ها در یک رشته انجام می‌شوند.

وقتی یک قطعه جاوااسکریپت سنگین اجرا می‌شود، مثلاً یک اسکریپت ۴۰۰ میلی‌ثانیه‌ای، در آن مدت، Main Thread کاملاً اشغال است. اگر کاربر در این فاصله روی دکمه‌ای کلیک کند، مرورگر آن کلیک را ثبت می‌کند ولی نمی‌تواند به آن پاسخ دهد تا اسکریپت تمام شود. این تأخیر، همان چیزی است که TBT می‌سنجد.

سه ویژگی Long Task که TBT را تشدید می‌کنند:

  • طولانی بودن: هرچه Task طولانی‌تر باشد، سهم بیشتری از آن به TBT اضافه می‌شود.
  • تعداد بالا: چند Task متوسط ۲۰۰ میلی‌ثانیه‌ای، TBT بدتری از یک Task بزرگ ۴۰۰ میلی‌ثانیه‌ای می‌سازد.
  • زمان‌بندی بد: اگر Long Taskها همزمان با ورود کاربر باشند (مثلاً در ثانیه‌های اول بارگذاری)، تجربه بدتر است.

تفاوت TBT با FCP، TTI و INP

در اکوسیستم Core Web Vitals، معیارهای متعددی وجود دارند که هرکدام بعد متفاوتی از تجربه را می‌سنجند. تفاوت‌های کلیدی:

معیارچه چیزی را می‌سنجد؟ارتباط با TBT
FCPزمان نمایش اولین محتواشروع پنجرهٔ سنجش TBT
TTIزمان آماده‌شدن کامل سایت برای تعاملپایان پنجرهٔ سنجش TBT
INPزمان پاسخ به آخرین تعامل کاربرTBT پیش‌بینی‌کنندهٔ INP است
TBTمجموع مسدودسازی بین FCP و TTIخودِ معیار

نکتهٔ ظریفی که در پروژه‌ها زیاد به کارم می‌آید: TBT یک معیار لابراتوار است، نه میدانی. یعنی در گزارش‌های CrUX (Chrome User Experience Report) نمی‌بینید. به همین دلیل، بعضی تیم‌ها آن را نادیده می‌گیرند. اما تجربهٔ من نشان می‌دهد TBT خوب، تقریباً همیشه به INP خوب منجر می‌شود. اگر TBT خوب باشد ولی INP بد، معمولاً یک مؤلفهٔ میدانی مانند شبکهٔ کاربر مقصر است. تفاوت دقیق TBT و INP را در INP چیست و چه تأثیری بر تجربه کاربر دارد؟ باز کرده‌ام.

چگونه TBT را اندازه بگیریم؟

اندازه‌گیری TBT دو لایه دارد: اندازه‌گیری خودکار با ابزارها و اندازه‌گیری دستی با DevTools. هر دو روش، مکمل یکدیگرند.

روش خودکار

ابزارهایی مثل PageSpeed Insights، Lighthouse در Chrome DevTools و WebPageTest، TBT را به‌طور خودکار محاسبه می‌کنند. این ابزارها یک اجرای آزمایشی روی سرور خودشان انجام می‌دهند و با شبیه‌سازی یک موبایل میان‌رده با اینترنت کند، TBT را می‌سنجند. تفاوت‌های این ابزارها را در بهترین ابزارهای تست سرعت سایت باز کرده‌ام.

روش دستی در Chrome DevTools

اگر می‌خواهید دقیقاً بفهمید کدام کد TBT را می‌سازد، باید از Performance Panel در Chrome DevTools استفاده کنید:

  1. DevTools را باز کنید و به تب Performance بروید.
  2. گزینهٔ Screenshots و Web Vitals را فعال کنید.
  3. دکمهٔ Record را بزنید و صفحه را ریلود کنید.
  4. بعد از بارگذاری کامل، Stop را بزنید.
  5. در بخش Timings، به‌دنبال نوار قرمز TBT بگردید.
  6. روی Long Taskها کلیک کنید تا کد مسئول مشخص شود.

این روش، دقیق‌ترین راه تشخیص ریشهٔ TBT است. در تجربهٔ خودم، معمولاً سه کد مقصر پیدا می‌شوند: یک اسکریپت تجزیه‌وتحلیل خارجی، یک اسلایدر/پاپ‌آپ سنگین، یا کد قالب که تا DOM ساخته نشده اجرا می‌شود.

ابزارهای اندازه‌گیری TBT

برای سنجش دقیق TBT، این ابزارها را در پروژه‌ها استفاده می‌کنم:

  • PageSpeed Insights: سریع‌ترین راه. در بخش Diagnostics، TBT را نشان می‌دهد و کدهای مقصر را فهرست می‌کند.
  • Lighthouse در Chrome DevTools: دقیق‌تر از PageSpeed برای تحلیل محلی، با گزارش تفصیلی هر Long Task.
  • WebPageTest: اگر می‌خواهید TBT را از چند موقعیت جغرافیایی و روی دستگاه‌های مختلف بسنجید.
  • Chrome DevTools Performance Panel: برای تحلیل عمیق و یافتن دقیق کد مسئول.
  • DebugBear یا Treo: ابزارهای پولی که پایش مداوم TBT و روند آن در طول زمان را ارائه می‌دهند.

روش ترکیبی من: اول با PageSpeed Insights یک تصویر کلی می‌گیرم. بعد با Lighthouse محلی تحلیل می‌کنم. در آخر با Performance Panel، دقیقاً همان کدی که TBT را می‌سازد شناسایی می‌کنم. این سه‌گانه، در همهٔ پروژه‌ها کار می‌کند. توضیحات بیشتر در ابزارهای سنجش Core Web Vitals کدامند؟

پنج عامل اصلی ایجاد TBT بالا

در بازبینی سایت‌های با TBT بالا، پنج عامل تکرار می‌شوند:

عامل اول: اسکریپت‌های مسدودکننده رندر

هر جاوااسکریپتی که در head تزریق شود و با ویژگی async یا defer بار نشود، اجرای صفحه را متوقف می‌کند. اگر این اسکریپت سنگین باشد، TBT به‌سرعت بالا می‌رود. راه‌حل: همیشه از async یا defer استفاده کنید.

عامل دوم: افزونه‌های سنگین با جاوااسکریپت زیاد

در وردپرس، افزونه‌های اسلایدر، پاپ‌آپ، تحلیل و ابزارهای چت، معمولاً کدهای جاوااسکریپتی سنگین دارند که در Main Thread اجرا می‌شوند. یک افزونهٔ اسلایدر می‌تواند ۲۰۰ میلی‌ثانیه به TBT اضافه کند. راهنمای کامل در افزونه‌ها وردپرس چگونه روی سرعت سایت اثر می‌گذارند؟

عامل سوم: DOM عمیق و تعداد نود بالا

هرچه DOM عمیق‌تر و پرحجم‌تر باشد، فرآیند پردازش آن طولانی‌تر است. اگر بیش از ۱۵۰۰ نود در DOM داشته باشید، TBT به‌طور طبیعی بالا می‌رود. مسئلهٔ عمق DOM در چرا بعضی قالب‌های وردپرس سایت را کند می‌کنند؟ باز کرده‌ام.

عامل چهارم: عملیات همگام (Sync) سنگین

عملیات‌هایی مثل Loopهای بزرگ، ترتیب‌دهی آرایه‌های بزرگ، یا Parsing متون طولانی، اگر به‌صورت همگام اجرا شوند، Main Thread را اشغال می‌کنند. راه‌حل: شکستن کار به تکه‌های کوچک یا انتقال به Web Worker.

عامل پنجم: بارگذاری ترتیبی اسکریپت‌ها

اگر ده اسکریپت به‌صورت ترتیبی بار شوند، هرکدام منتظر تمام شدن قبلی می‌ماند. این الگو TBT را افزایش می‌دهد. راه‌حل: بارگذاری موازی با preload و defer.

کاهش TBT: هشت تکنیک عملی

برای کاهش TBT، هشت تکنیک که در پروژه‌ها استفاده می‌کنم:

تکنیک یکم: Delayed JavaScript Execution

اسکریپت‌هایی که برای رندر اولیه لازماند را با defer بار کنید. اسکریپت‌های غیرضروری مثل چت و آنالیتیکس را با تأخیر اجرا کنید. اکثر افزونه‌های کش مدرن این قابلیت را دارند.

تکنیک دوم: Code Splitting

به‌جای ارسال یک فایل جاوااسکریپت بزرگ، آن را به تکه‌های کوچک‌تر بشکنید و هر تکه فقط وقتی لازم است بار شود. این تکنیک در فریم‌ورک‌های مدرن مثل React و Vue استاندارد است، ولی در وردپرس معمولاً دستی اعمال می‌شود.

تکنیک سوم: انتقال محاسبات سنگین به Web Worker

اگر بخشی از کد شما محاسبات سنگین دارد که به DOM نیازی ندارد، آن را به Web Worker منتقل کنید. Web Worker در رشته‌ای جداگانه اجرا می‌شود و Main Thread را مسدود نمی‌کند.

تکنیک چهارم: کاهش حجم DOM

تعداد نودهای DOM را کم کنید. اگر از صفحه‌ساز استفاده می‌کنید، تعداد لایه‌های تودرتو را کاهش دهید. از lazy-load برای بخش‌های پایین صفحه استفاده کنید.

تکنیک پنجم: بهینه‌سازی Event Listenerها

از Event Listenerهای passive برای رویدادهای scroll و touch استفاده کنید. این کار باعث می‌شود مرورگر بتواند قبل از اجرای اسکریپت شما، به تعامل کاربر پاسخ دهد.

تکنیک ششم: استفاده از requestIdleCallback

کارهای غیرضروری که باید در زمان اجرا انجام شوند، با requestIdleCallback زمان‌بندی کنید تا در زمان بیکاری Main Thread اجرا شوند.

تکنیک هفتم: بهینه‌سازی اسکریپت‌های شخص ثالث

اسکریپت‌های شخص ثالث (تحلیل، تبلیغات، چت) معمولاً بیشترین سهم را در TBT دارند. آن‌ها را با تأخیر بار کنید یا کلاً حذف کنید. راهنمای دقیق در بهینه‌سازی جاوااسکریپت.

تکنیک هشتم: کاهش اندازه Bundle

حجم کل جاوااسکریپت سایت را با minify، tree-shaking و حذف کدهای استفاده‌نشده کاهش دهید. هر کیلوبایت کمتر، TBT را کمی بهتر می‌کند.

TBT در وردپرس: چرا این معیار برای سایت‌های وردپرسی مهم است؟

وردپرس، به‌خاطر ساختار افزونه‌محورش، در خطر بالای TBT قرار دارد. هر افزونه‌ای که نصب می‌کنید، می‌تواند جاوااسکریپت اضافه کند. پنج منبع اصلی TBT در سایت‌های وردپرسی:

  1. افزونه‌های اسلایدر و پاپ‌آپ: معمولاً ۱۵۰ تا ۳۰۰ میلی‌ثانیه به TBT اضافه می‌کنند.
  2. صفحه‌سازها: خروجی HTML و JS آن‌ها، DOM را عمیق و سنگین می‌کند.
  3. افزونه‌های چت و پشتیبانی: کدهای شخص ثالث، اغلب بین ۱۰۰ تا ۲۰۰ میلی‌ثانیه TBT می‌سازند.
  4. افزونه‌های بهینه‌سازی ناموفق: بعضی افزونه‌هایی که ادعای بهینه‌سازی می‌کنند، خودشان TBT را بالا می‌برند.
  5. اسکریپت‌های قالب: اگر قالب شما با جاوااسکریپت نسل قبل نوشته شده، معمولاً TBT بالایی تولید می‌کند.

راهکارهای عملی در وردپرس: اول، تعداد افزونه‌های جاوااسکریپتی را کم کنید. دوم، از افزونهٔ کش با قابلیت Delay JavaScript Execution استفاده کنید. سوم، اگر قالب شما جاوااسکریپت سنگین دارد، به قالب سبک مهاجرت کنید. تفاوت‌ها در قالب سبک وردپرس چیست؟ و راهنمای کلی در Core Web Vitals در وردپرس چگونه بهبود می‌یابد؟

اشتباهات رایج در سنجش و کاهش TBT

پنج اشتباه که در پروژه‌ها زیاد دیده‌ام:

  • قناعت به نمرهٔ کلی Lighthouse: نمرهٔ ۹۵ کلی می‌تواند TBT بد داشته باشد. همیشه به عدد هر معیار جدا نگاه کنید.
  • فرض این‌که TBT لابراتوار با میدان یکی است: شرایط اجرای آزمایشگاهی، همیشه با شرایط کاربر واقعی متفاوت است. دو عدد را جدی بگیرید.
  • فقط با حذف اسکریپت‌ها به‌دنبال کاهش TBT: کاهش TBT به‌معنی حذف قابلیت‌ها نیست، به‌معنی بهینه‌سازی زمان اجرا است.
  • بی‌توجهی به اسکریپت‌های شخص ثالث: بسیاری از تیم‌ها فقط روی کد خودشان تمرکز می‌کنند و اسکریپت‌های خارجی مثل آنالیتیکس را نادیده می‌گیرند.
  • عدم پایش مداوم: TBT با هر افزونه و آپدیت می‌تواند تغییر کند. بدون پایش ماهانه، افت تدریجی کشف نمی‌شود.

پرسش و پاسخ‌های پرتکرار درباره TBT

TBT چیست به زبان ساده؟

TBT یا Total Blocking Time، مجموع زمان‌هایی است که در آن، مرورگر نمی‌تواند به تعامل کاربر پاسخ دهد چون رشتهٔ اصلی‌اش توسط اجرای کد سنگین اشغال شده. هر Taskی که بیش از ۵۰ میلی‌ثانیه طول بکشد، Long Task نام دارد و بخش بیش از ۵۰ میلی‌ثانیه‌اش به TBT اضافه می‌شود. مقدار خوب TBT زیر ۲۰۰ میلی‌ثانیه است.

تفاوت TBT و INP چیست؟

TBT یک معیار لابراتوار است که در بازهٔ بین FCP و TTI اندازه‌گیری می‌شود و مجموع مسدودسازی Main Thread را می‌سنجد. INP یک معیار میدانی است که تجربهٔ واقعی کاربران در تعامل با سایت را می‌سنجد. TBT و INP با هم مرتبط‌اند: TBT خوب معمولاً به INP خوب منجر می‌شود. اما گاهی TBT خوب و INP بد دیده می‌شود، معمولاً به‌خاطر شرایط شبکه کاربر.

چرا TBT در Core Web Vitals نیست؟

Core Web Vitals سه معیار اصلی دارد: LCP، INP و CLS. TBT یکی از معیارهای مکمل است که در Lighthouse استفاده می‌شود ولی رسماً بخشی از Core Web Vitals نیست. دلیل این انتخاب، تمرکز گوگل بر معیارهای میدانی است، در حالی که TBT یک معیار لابراتوار است. اما به‌عنوان ابزار تشخیص، TBT ارزش زیادی دارد. توضیحات کامل در Core Web Vitals چیست و چرا گوگل بر آن تأکید دارد؟

چگونه می‌توانم TBT را در Chrome DevTools ببینم؟

تب Performance را باز کنید، گزینهٔ Web Vitals را فعال کنید و ضبط را شروع کنید. در پایان، در بخش Timings، نوار TBT قابل مشاهده است. همچنین در بخش Bottom-Up، فهرست کدهایی که بیشترین سهم را در TBT دارند نمایش داده می‌شود. این دقیق‌ترین راه تشخیص کد مسئول TBT است.

آیا TBT خوب به‌معنی سرعت خوب است؟

نه، این دو معیار مستقل از هم هستند. ممکن است سایت شما LCP خوب داشته باشد ولی TBT بد. یعنی صفحه سریع باز می‌شود اما هنگام تعامل کاربر، چند لحظه بی‌پاسخ می‌ماند. تجربهٔ کاربر به هر دو معیار حساس است. یعنی سایت باید هم سریع باز شود و هم سریع پاسخ دهد. این مفهوم دوگانه در چگونه Core Web Vitals را بهبود دهیم؟ باز شده است.

کدام اسکریپت‌ها بیشترین سهم را در TBT دارند؟

سه دسته: اول، اسکریپت‌های شخص ثالث مثل چت، آنالیتیکس و تبلیغات. دوم، اسکریپت‌های اسلایدر و پاپ‌آپ که در وردپرس معمولاً با افزونه‌های سنگین ارائه می‌شوند. سوم، اسکریپت‌های قالب که در head اجرا می‌شوند و با async یا defer بار نمی‌شوند. این سه دسته، بیش از هشتاد درصد TBT در سایت‌های معمول را می‌سازند.

آیا TBT در موبایل و دسکتاپ متفاوت است؟

بله، و این تفاوت بسیار مهم است. TBT در موبایل معمولاً دو تا سه برابر دسکتاپ است، چون پردازندهٔ موبایل ضعیف‌تر است و اسکریپت‌ها زمان بیشتری برای اجرا نیاز دارند. همیشه TBT را از منظر موبایل بسنجید، چون معیار واقعی کاربران موبایل است. همین تفاوت در چگونه Core Web Vitals را در موبایل بهبود دهیم؟ باز شده است.

سخن پایانی: TBT به‌عنوان صدای درونی سایت

TBT یکی از آن معیارهایی است که تا وقتی سایت خوب کار می‌کند، کسی به آن فکر نمی‌کند. اما روزی که کاربران شروع به شکایت از کندی و بی‌پاسخی می‌کنند، TBT اولین توضیح منطقی است. این معیار به شما می‌گوید سایت شما در آن لحظه‌های حساس بین لمس و واکنش، چه تجربه‌ای به کاربر می‌دهد. تفاوت بین سایتی که سریع باز می‌شود ولی کند پاسخ می‌دهد و سایتی که سریع باز می‌شود و سریع پاسخ می‌دهد، دقیقاً همین است.

پیشنهاد عملی من سه گام است. اول، همین امروز TBT سایت خود را با PageSpeed Insights یا Lighthouse بسنجید. اگر بالای ۲۰۰ میلی‌ثانیه بود، آن را یک اولویت کنید. دوم، با Chrome DevTools Performance Panel کد مسئول را پیدا کنید. در تجربهٔ من، معمولاً یک یا دو اسکریپت مسئول بیش از نیمی از TBT هستند. سوم، سه ماه آینده هر ماه TBT را پایش کنید، چون با هر افزونه و آپدیت جدید، می‌تواند تغییر کند.

اگر تجربه‌ای از کاهش TBT در پروژه‌های خودتان دارید — به‌خصوص اگر یک کد غیرمنتظره مقصر بوده یا تکنیکی کشف کرده‌اید که در این مقاله نبوده — برایم بنویسید. همین تجربه‌های میدانی، به خوانندهٔ بعدی کمک می‌کند سایت سریع‌تر و پاسخ‌دهنده‌تری بسازد. ⚡