جاری‌سازی HTML نامرتب (OOO)

جاری‌سازی HTML نامرتب (OOO) (که با نام «به‌روزرسانی‌های جزئی اعلانی» نیز شناخته می‌شود) جایگزینی برای پردازش خطی سنتی «بالا به پایین» HTML است. این ویژگی به توسعه‌دهندگان امکان می‌دهد جای‌بان‌ها را زودتر در سند تعریف کنند و آن‌ها را با محتوایی که بعداً در همان جریان شبکه یا ازطریق میاناهای برنامه‌سازی کاربردی جاری‌سازی جاوا اسکریپت امری جدید می‌رسد «وصله» کنند.

نمای کلی سریع

این ویژگی از دو سازوکار اصلی تشکیل شده است:

  1. وصله کردن اعلانی (مبتنی بر HTML): از دستورالعمل‌های پردازش جدید (<?marker>، <?start>، <?end>) و <template for> برای جابه‌جا کردن محتوا در DOM هنگام جاری‌سازی از سرور استفاده می‌کند.
  2. تنظیم و جاری‌سازی امری (مبتنی بر JS): مجموعه‌ای از روش‌های جدید (مثلاً streamHTML()، setHTMLUnsafe()) که امکان تنظیم HTML یا جاری‌سازی مستقیم جریان‌های خواندنی به عناصر DOM را با عملکرد بومی و اجرای اختیاری اسکریپت فراهم می‌کند.

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

  • اولویت‌بندی محتوای بالای خط تا: ابتدا میانای کاربر حیاتی (سرصفحه، قهرمان، پیمایش اصلی، محتوای اصلی) را جاری‌سازی کنید. از جای‌بان‌ها برای مؤلفه‌های «گران» یا با اولویت پایین‌تر مانند نظرات، آگهی‌ها، یا محتوای مرتبط استفاده کنید.
  • پیاده‌سازی حالت‌های بارگیری بومی: از نشانگرهای <?start> و <?end> برای پیچیدن محتوای بازگشتی استفاده کنید. مرورگر به‌طور خودکار همه چیزهای بین این نشانگرها را با <template for> مربوطه جایگزین می‌کند.
  • به‌حداقل رساندن «تغییر چیدمان تجمعی» (CLS): همیشه ابعاد پایداری برای جای‌بان‌ها ارائه دهید. اگر اندازه نهایی محتوا مشخص نیست، از صفحه‌های اسکلتی یا CSS aspect-ratio برای رزرو فضا و جلوگیری از جابه‌جایی‌های ناگهانی استفاده کنید.
  • دسترس‌پذیری و مدیریت تمرکز: توجه داشته باشید که به‌روزرسانی‌های نامرتب می‌تواند کاربران صفحه‌خوان را گیج کند. از مناطق aria-live برای به‌روزرسانی‌های مهم استفاده کنید و مطمئن شوید که اگر جای‌بان حاوی عنصر فعال جایگزین شد، تمرکز ازبین نرود.

جزئیات پیاده‌سازی

۱. نشانگرهای HTML اظهاری

مرورگر به‌دنبال دستورالعمل‌های پردازش خاصی می‌گردد تا مشخص کند محتوا کجا باید وصله شود.

<!-- A simple insertion point -->
<div id="sidebar">
  <?marker name="dynamic-comments">
</div>

<!-- A replacement range with loading state -->
<main>
  <?start name="main-content">
    <div class="skeleton">Loading content...</div>
  <?end>
</main>

... (other content) ...

<!-- Later in the same stream, provide the content -->
<template for="dynamic-comments">
  <div class="comments">...</div>
</template>

<template for="main-content">
  <article>
    <h1>The Real Content</h1>
    <p>This replaces the skeleton div automatically.</p>
  </article>
</template>

وقتی <template> جایگزین نقطه درج می‌شود، آن نقطه درج دیگر وجود ندارد و نمی‌توان دوباره از آن استفاده کرد. بااین‌حال، <template> ممکن است حاوی نقاط درج باشد که می‌توان بعداً در جاری‌سازی از آن‌ها استفاده کرد.

 <?start name="replaced-content">
  <div class="skeleton">
<?end>
<!-- Later in the same stream, provide initial content -->
<template for="replaced-content">
  <?start name="replaced-content">
    <div>Quickly computed result</div>
  <?end>
</template>
<!-- Later in the same stream, provide full content -->
<template for="replaced-content">
  <?start name="replaced-content">
    <div>Full result</div>
  <?end>
</template>

۲. جاری‌سازی JS امری

مرورگر مجموعه‌ای از ۲۴ روش (۶ کنش، هرکدام با ۴ نوع) را برای به‌روزرسانی DOM به‌صورت ایستا (از رشته) یا ازطریق جاری‌سازی ارائه می‌دهد.

ماتریس مرجع میانای برنامه‌سازی کاربردی

کنش ثابت (ایمن) جاری‌سازی (ایمن) ثابت (ناامن) جاری‌سازی (غیرایمن)
تنظیم setHTML() streamHTML() setHTMLUnsafe() streamHTMLUnsafe()
جایگزین کردن replaceWithHTML() streamReplaceWithHTML() replaceWithHTMLUnsafe() streamReplaceWithHTMLUnsafe()
قبل beforeHTML() streamBeforeHTML() beforeHTMLUnsafe() streamBeforeHTMLUnsafe()
پیش‌افزودن prependHTML() streamPrependHTML() prependHTMLUnsafe() streamPrependHTMLUnsafe()
افزودن appendHTML() streamAppendHTML() appendHTMLUnsafe() streamAppendHTMLUnsafe()
بعداز afterHTML() streamAfterHTML() afterHTMLUnsafe() streamAfterHTMLUnsafe()

مفاهیم کلیدی

  • ایمن دربرابر ناایمن:
    • روش‌های ایمن (مانند setHTML()) به‌طور پیش‌فرض از یک پاک‌کننده داخلی برای حذف محتوای بالقوه خطرناک مانند برچسب‌های <script> استفاده می‌کنند. می‌توانید یک شیء Sanitizer سفارشی را در گزینه‌ها ارسال کنید تا علاوه‌بر پاک‌کننده پیش‌فرض اعمال شود.
    • روش‌های ناامن (مثلاً setHTMLUnsafe()) به‌طور پیش‌فرض پاک‌سازی نمی‌کنند، اما همچنان می‌توانید Sanitizer سفارشی را ارسال کنید. برای اینکه به دستورات اجازه دهید در محتوای جدید اجرا شوند، باید صریحاً { runScripts: true } را در گزینه‌ها ارسال کنید. مهم: فقط از روش‌های ناامن با محتوای مورداعتماد استفاده کنید که روش‌های ایمن کار نمی‌کنند.
  • ایستا دربرابر جاری‌سازی:
    • روش‌های ایستا رشته‌ای (یا TrustedHTML) را می‌گیرند و آن را فوراً اعمال می‌کنند.
    • روش‌های جاری‌سازی WritableStream را برمی‌گردانند. این کار به شما امکان می‌دهد محتوا را (مثلاً از پاسخ fetch) مستقیماً به DOM منتقل کنید و مرورگر آن را به‌صورت تدریجی با رسیدن بخش‌ها ارائه خواهد کرد.

مثال: جاری‌سازی کردن Fetch Response

می‌توانید پاسخ‌های واکشی را مستقیماً بدون مدیریت دستی تکه‌ها به DOM منتقل کنید.

const main = document.querySelector('main');
const response = await fetch('/api/partial-update');

// Pipe the stream directly into the element
await response.body
  .pipeThrough(new TextDecoderStream())
  .pipeTo(main.streamHTMLUnsafe({ runScripts: true }));

// Or use the `textStream()` convenience method which streams directly without needing the intermediate `TextDecoderStream()` step
await response
  .textStream()
  .pipeTo(main.streamHTMLUnsafe({ runScripts: true }))

ماتریس مرجع مورد استفاده

  • معماری جزیره‌ای: مؤلفه‌های تعاملی مستقل را روی HTML ایستا بدون زمان اجرای چارچوب کامل هیدراته کنید.
  • بلوک‌های «گران» به‌تعویق‌افتاده: پوسته صفحه را فوراً ارائه می‌دهد و مؤلفه‌های سنگین پایگاه داده را به‌محض دردسترس قرار گرفتن جاری‌سازی می‌کند.
  • به‌روزرسانی‌های برنامه تک‌صفحه‌ای (SPA): انتقال‌های بزرگ UI را در SPAها بااستفاده از streamHTML() جاری‌سازی کنید، به‌جای اینکه منتظر پایه‌بار JSON کامل و ساخت DOM دستی بمانید.

الگوهای نامناسب و هشدارها (این کار را نکنید)

  • از جاری‌سازی OOO برای همه چیز استفاده نکنید. تکه‌تکه کردن بیش‌ازحد صفحه می‌تواند پیچیدگی جاری‌سازی را افزایش دهد و اگر مرورگر زمان زیادی را صرف وصله کردن گره‌های کوچک کند، ممکن است محتوا را به‌تأخیر بیندازد.
  • «انواع مطمئن» را نادیده نگیرید. هنگام استفاده از روش‌های *Unsafe در محیط‌هایی که «انواع مطمئن» در آن‌ها اعمال می‌شود، مطمئن شوید که درصورت لزوم، شیء خط‌مشی پاک‌سازی‌شده را ارسال می‌کنید.
  • ترتیب اجرای اسکریپت را فرض نکنید. اسکریپت‌های داخل <template for> به‌محض وصله شدن به سند اجرا خواهند شد. به اجرای آن‌ها در توالی خاصی نسبت‌به دیگر الگوهای معوقه اتکا نکنید.
  • بدون استراتژی شبیه‌ساز مرورگر استفاده نکنید. مطمئن شوید که یک جایگزین دارید یا از شبیه‌سازهای مرورگر (html-setters-polyfill و template-for-polyfill) برای پشتیبانی از مرورگرهای موردنیازتان استفاده کنید تا زمانی که این ویژگی به «خط پایه» تبدیل شود.

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

می‌توانید از شبیه‌سازهای مرورگر مثل template-for-polyfill و html-setters-polyfill برای شبیه‌سازی سطح میانای برنامه‌سازی کاربردی برای مرورگرهای غیرپشتیبان استفاده کنید.

مرورگرهای بدون پشتیبانی html-processing-instructions، <?marker>، <?start>، و <?end> را به‌عنوان نظر تجزیه می‌کنند. template-for-polyfill همچنان این نظرات را به‌عنوان نشانگر تشخیص می‌دهد، بنابراین نحو دستورالعمل پردازش را برای همه مرورگرها یکسان نگه دارید. نشانگرها را به‌عنوان نظر یا عنصر HTML برای مرورگرهای غیرپشتیبانی‌کننده بازنویسی نکنید.