آزمایش آ/ب سمت کارخواه بدون پرش

ویژگی‌های وب: blocking="render"

مشکل

ابزارهای آزمایش A/B سمت کارخواه با بار کردن اسکریپتی کار می‌کنند که DOM را پس‌از اینکه مرورگر ساخت صفحه را شروع کرد اصلاح می‌کند. بدون مداخله، کاربر محتوای اصلی را به‌طور خلاصه قبل‌از اینکه به متغیر آزمایش چشمک بزند یا فلاش بزند، می‌بیند. پلاتفرم‌های آزمایشی از گذشته با «قطعه کدهای ضدلرزش» که کل صفحه را با opacity: 0 پنهان می‌کنند تا زمانی که اسکریپت آزمایش تمام شود یا زمان دلخواهی (معمولاً ۴ ثانیه) سپری شود، این مشکل را حل کرده‌اند. این رویکرد پردازش تدریجی را فدا می‌کند، باعث کلیک‌های تصادفی روی محتوای نامرئی می‌شود، و چرخه‌های رنگ‌آمیزی غیرضروری ایجاد می‌کند.

راه‌حل

مشخصه blocking=render به عنصر <script> یا <link> که در <head> قرار دارد اجازه می‌دهد تا زمانی که منبع واکشی و اجرا نشده است، پرداز را مسدود کند (اما تجزیه را مسدود نکند). این کار به اسکریپت‌های آزمایش همان رفتار مسدودکننده رندر را می‌دهد که برگه‌های سبک نگارش به‌طور پیش‌فرض دارند و تضمین می‌کند که مرورگر هرگز صفحه را تا زمانی که متغیر آزمایش اعمال نشده است، رنگ‌آمیزی نکند. بدون ترفندهای شفافیت، بدون زمان‌بندی‌های دلخواه، و بدون چشمک زدن.

راهبرد پیاده‌سازی

  1. اجباری: اسکریپت آزمایش را در سند <head> قرار دهید و blocking="render" را اضافه کنید.
  2. اجباری: مطمئن شوید که دستورگان دارای type="module" (ترجیحاً برای دستورگان‌های درون‌خطی) یا async (ترجیحاً برای دستورگان‌های خارجی با مقدار src) باشد.
  3. باید اسکریپت آزمایش کوچک و سریع باشد. ازآنجایی‌که رندر کردن تا زمان اجرای متن مسدود می‌شود، متن بزرگ یا کند مستقیماً اولین رنگ‌آمیزی را به‌تأخیر می‌اندازد.
  4. از blocking="render" در دستورات اجرایی که لازم نیست قبل‌از اولین رنگ‌آمیزی اجرا شوند استفاده نکنید. این ویژگی فقط برای اسکریپت‌هایی درنظر گرفته شده است که برونداد آن‌ها باید در پردازش اولیه قابل‌مشاهده باشد.
  5. blocking="render" را برای دستورگان‌های خارج از <head> اعمال نکنید. فقط اسکریپت‌های موجود در <head> می‌توانند پردازش را مسدود کنند.

راهنمای پیاده‌سازی

راه‌اندازی پایه

اجباری: اسکریپت آزمایش را با هر دو async و blocking="render" بار کنید. مشخصه async تضمین می‌کند که دستورگان تجزیه HTML را مسدود نمی‌کند (مرورگر درحین واکشی دستورگان به ساخت DOM ادامه می‌دهد). مشخصه blocking="render" تضمین می‌کند که مرورگر تا زمانی که اسکریپت اجرا نشده است، چیزی را رنگ‌آمیزی نکند.

<head>
  <!--
    MANDATORY: Both `async` and `blocking="render"` are required.
    - `async`: Prevents parser-blocking, so the DOM is built in parallel.
    - `blocking="render"`: Holds rendering until the script executes,
      ensuring experiment changes are applied before the user sees anything.
  -->
  <script
    src="https://cdn.example.com/experiment-sdk.js"
    async
    blocking="render"
  ></script>
</head>

درحال بار کردن سبک‌های مختص آزمایش

اگر آزمایش به برگه سبک نگارش متغیر نیاز دارد، از blocking="render" در عنصر <link> استفاده کنید. شیوه‌نامه‌ها در <head> ازقبل به‌طور پیش‌فرض پرداز را مسدود می‌کنند، اما شیوه‌نامه‌هایی که به‌طور پویا تزریق شده‌اند یا آن‌هایی که ازطریق اسکریپت اضافه شده‌اند این کار را نمی‌کنند. وقتی برگه سبک نگارش به‌طور پویا اضافه می‌شود یا وقتی می‌خواهید صریحاً قصدتان را بیان کنید، از blocking="render" به‌طور صریح استفاده کنید.

<head>
  <!--
    DO: Use blocking="render" on experiment stylesheets that are
    dynamically inserted or conditionally loaded by the experiment SDK.
    This ensures variant styles are applied before first paint.
  -->
  <link
    rel="stylesheet"
    href="https://cdn.example.com/experiment-variant-b.css"
    blocking="render"
  >
</head>

Inline Experiment Script

اگر منطق آزمایش به‌اندازه کافی سبک است که بتوان آن را به‌صورت درون‌خطی قرار داد، از یک اسکریپت ماژول درون‌خطی با blocking="render" استفاده کنید. این زمانی مفید است که منطق آزمایش پیکربندی را واکشی می‌کند و تغییرات DOM را مستقیماً اعمال می‌کند.

<head>
  <!--
    DO: Use an inline module script when the experiment logic is small.
    Module scripts are deferred by default (non-parser-blocking),
    and blocking="render" ensures rendering waits for execution.
  -->
  <script type="module" blocking="render">
    // Fetch the experiment configuration from your testing platform.
    const config = await fetch('/api/experiment?id=homepage-cta')
      .then(res => res.json());

    // Apply the variant by setting a data attribute on <html>.
    // CSS rules keyed to this attribute will style the variant.
    document.documentElement.dataset.variant = config.variant;
  </script>

  <style>
    /* Default styles (control group) */
    .cta-button {
      background-color: blue;
    }

    /* Variant B styles, activated by the data attribute */
    [data-variant="b"] .cta-button {
      background-color: green;
    }
  </style>
</head>

روال‌های مطلوب

  • اجباری: اسکریپت آزمایش باید سریع اجرا شود. یک اسکریپت کند، همه پردازش‌ها را به تأخیر می‌اندازد. بودجه عملکردی (مثلاً زمان اجرای کمتر از ۱۰۰ میلی‌ثانیه) برای اسکریپت مسدودکننده رندر تنظیم کنید.
  • باید منطق آزمایش سنگین را از اسکریپت مسدودکننده رندر جدا کنید. یک کد کوچک مسدودکننده رندر را که گونه را اعمال می‌کند بار کنید، سپس اسکریپت‌های سنگین‌تر ردیابی یا تجزیه‌وتحلیل را به‌طور جداگانه با async یا defer (بدون blocking="render") بار کنید.
  • باید از مشخصه داده در <html> یا <body> برای نشان دادن گونه فعال استفاده کنید و از گزینشگرهای CSS کلیدشده به آن مشخصه برای سبک‌بندی گونه استفاده کنید. این کار از دستکاری مستقیم DOM در اسکریپت مسدودکننده رندر جلوگیری می‌کند.
  • از blocking="render" در تجزیه‌وتحلیل، ردیابی، یا دیگر اسکریپت‌های غیردیداری استفاده نکنید. فقط اسکریپت‌هایی که باید آنچه را کاربر در اولین رنگ‌آمیزی می‌بیند تغییر دهند باید رندر کردن را مسدود کنند.
  • blocking="render" را با قطعه‌های ضدلرزش قدیمی ترکیب نکنید. هر دو یک مشکل را حل می‌کنند؛ استفاده از هر دو باعث تأخیرهای غیرضروری می‌شود.

راهبردهای جایگزین

مشخصه blocking در همه مرورگرها پشتیبانی نمی‌شود. در مرورگرهایی که از آن پشتیبانی نمی‌کنند، این مشخصه نادیده گرفته می‌شود و اسکریپت با رفتار پیش‌فرض خود (async در مثال‌های بالا) بار می‌شود که ممکن است منجر به لرزش شود. برای جلوگیری از لرزش در مرورگرهای پشتیبانی‌نشده، به بازگشت نیاز است.

گزینه جایگزین: تکه‌کد ضدلرزش نور

باید: از قطعه کد ضدلرزش سبک به‌عنوان جایگزین فقط زمانی استفاده کنید که blocking="render" پشتیبانی نمی‌شود. پشتیبانی از تشخیص ویژگی و رد شدن از بازگشت در مرورگرهایی که آن را به‌صورت داخلی مدیریت می‌کنند.

<head>
  <!--
    DO: Load the experiment script with blocking="render" for
    browsers that support it. This is the preferred approach.
  -->
  <script
    src="https://cdn.example.com/experiment-sdk.js"
    async
    blocking="render"
  ></script>

  <script>
    // DO: Only apply the anti-flicker fallback in browsers
    // that do not support blocking="render".
    if (!Object.hasOwn(HTMLScriptElement.prototype, 'blocking')) {
      // Hide the page until the experiment script runs.
      document.documentElement.classList.add('ab-loading');

      // DO: Set a timeout to reveal the page if the experiment
      // script takes too long. This prevents an indefinitely
      // blank page on slow connections. Adjust the timeout
      // to match your experiment SDK's expected load time.
      setTimeout(() => {
        document.documentElement.classList.remove('ab-loading');
      }, 4000);
    }
  </script>

  <style>
    /*
      DO: Use opacity to hide content during experiment loading.
      This is only applied when blocking="render" is unsupported.
    */
    .ab-loading {
      opacity: 0 !important;
    }
  </style>
</head>
// DO: In your experiment SDK's initialization callback,
// remove the fallback class to reveal the page.
function onExperimentReady() {
  document.documentElement.classList.remove('ab-loading');
}

ملاحظات دیگر

  1. تأثیر بر عملکرد: blocking="render" سرعت اولین رنگ‌آمیزی را با درستی بصری معاوضه می‌کند. «بزرگ‌ترین نقاشی دارای محتوا» (LCP) و «اولین نقاشی دارای محتوا» (FCP) را پایش کنید تا مطمئن شوید اسکریپت آزمایش تأخیر بیش‌ازحد اضافه نمی‌کند.
  2. قابلیت اطمینان اسکریپت شخص ثالث: اگر SDK آزمایش در یک CDN شخص ثالث میزبانی شود، قطعی CDN می‌تواند به‌طور کامل رندرینگ را مسدود کند. مرورگر از روش‌های اکتشافی وقفه زمانی خودش (که ممکن است طولانی‌تر از ۴ ثانیه باشد) استفاده می‌کند، اما هیچ وقفه زمانی تحت کنترل توسعه‌دهنده برای blocking="render" وجود ندارد. مطمئن شوید ارائه‌دهنده طرف سوم تضمین‌های قوی برای زمان فعال بودن دستگاه ارائه می‌دهد.
  3. جایگزین‌های سمت سرور: برای صفحه‌هایی که عملکرد آن‌ها حیاتی است، به‌جای آزمایش A/B سمت کارخواه، آزمایش A/B سمت سرور را درنظر بگیرید (که در آن سرور مستقیماً گونه صحیح را ارائه می‌دهد). رویکردهای سمت سرور، لرزش را به‌طور کامل و بدون هیچ‌گونه هزینه مسدود کردن رندر حذف می‌کنند. فقط زمانی‌که آزمایش سمت سرور امکان‌پذیر نیست، از blocking="render" سمت کارخواه استفاده کنید.