بث HTML غير المنظّم (OOO)

يُعدّ بث HTML غير المنظَّم (المعروف أيضًا باسم "التعديلات الجزئية التعريفية") بديلاً للمعالجة الخطية التقليدية لـ HTML من الأعلى إلى الأسفل. تسمح هذه الميزة للمطوّرين بتحديد العناصر النائبة في وقت مبكر في المستند و "تصحيحها" باستخدام المحتوى الذي يصل لاحقًا في مصدر الشبكة نفسه، أو من خلال واجهات برمجة تطبيقات جديدة لبث JavaScript.

نظرة عامة سريعة

تتألف الميزة من آليتَين أساسيتَين:

  1. التصحيح التعريفي (المستند إلى HTML): يستخدم تعليمات معالجة جديدة (<?marker> و<?start> و<?end>) و<template for> لتبديل المحتوى في نموذج DOM أثناء بثّه من الخادم.
  2. الإعدادات الإلزامية وعمليات البث (المستندة إلى JavaScript): مجموعة من الطرق الجديدة (مثل streamHTML() وsetHTMLUnsafe()) التي تتيح إعداد HTML أو توجيه عمليات البث القابلة للقراءة مباشرةً إلى عناصر DOM مع أداء أصلي وتنفيذ اختياري للنصوص البرمجية.

أفضل الممارسات

  • منح الأولوية للمحتوى في الجزء المرئي من الصفحة: يجب أولاً عرض واجهة المستخدم المهمة (العنوان، والصورة الرئيسية، والتنقّل الأساسي، والمحتوى الأساسي). استخدِم العناصر النائبة للمكوّنات "المكلفة" أو ذات الأولوية المنخفضة، مثل التعليقات أو الإعلانات أو المحتوى ذي الصلة.
  • تنفيذ حالات التحميل المدمجة مع المحتوى: استخدِم العلامتَين <?start> و<?end> لتضمين المحتوى الاحتياطي. يستبدل المتصفّح تلقائيًا كل ما بين هاتين العلامتين عند وصول <template for> المقابل.
  • الحدّ من متغيّرات التصميم التراكمية (CLS): يجب دائمًا توفير أبعاد ثابتة للعناصر النائبة. إذا كان حجم المحتوى النهائي غير معروف، استخدِم شاشات الهيكل أو السمة aspect-ratio في CSS لحجز مساحة ومنع حدوث تغييرات مفاجئة.
  • تسهيل الاستخدام وإدارة التركيز: يُرجى الانتباه إلى أنّ التحديثات غير المنظَّمة قد تربك مستخدمي قارئ الشاشة. استخدِم مناطق aria-live للتحديثات المهمة وتأكَّد من عدم فقدان التركيز في حال استبدال عنصر نائب يحتوي على العنصر النشط.

تفاصيل التنفيذ

1. علامات 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>

2. البث الإلزامي لـ JS

يوفّر المتصفّح مجموعة من 24 طريقة (6 إجراءات، لكل منها 4 صيغ) لتعديل نموذج DOM إما بشكل ثابت (من سلسلة) أو من خلال مصدر بيانات.

مرجع واجهة برمجة التطبيقات (API)

الإجراء ثابت (آمن) البث (آمن) ثابت (غير آمن) بث المحتوى (غير آمن)
ضبط 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

يمكنك توجيه استجابات fetch مباشرةً إلى 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): يمكنك بثّ عمليات انتقال كبيرة في واجهة المستخدم في التطبيقات من صفحة واحدة باستخدام streamHTML() بدلاً من انتظار حمولة JSON كاملة وإنشاء نموذج العناصر في المستند (DOM) يدويًا.

الأنماط المضادة والتحذيرات (لا تفعل ذلك)

  • لا تستخدموا البث المباشر خارج المكتب لكل شيء. يمكن أن يؤدي تقسيم الصفحة بشكل مفرط إلى زيادة تعقيد عملية البث وقد يؤدي إلى تأخير المحتوى إذا قضى المتصفّح وقتًا طويلاً في تجميع العُقد الصغيرة.
  • لا تتجاهل ميزة "الأنواع الموثوق بها". عند استخدام طرق *Unsafe في بيئات يتم فيها فرض "الأنواع الموثوق بها"، تأكَّد من تمرير عنصر سياسة تمّت تنقيته إذا لزم الأمر.
  • لا تفترض ترتيب تنفيذ النصوص البرمجية. سيتم تنفيذ النصوص البرمجية داخل <template for> فور تصحيحها في المستند. ولا تعتمد على تنفيذها في تسلسل محدّد بالنسبة إلى النماذج المؤجَّلة الأخرى.
  • لا تستخدِم هذه السمة بدون استراتيجية polyfill. تأكَّد من توفّر إجراء بديل أو استخدام رموز polyfill ‏ (html-setters-polyfill وtemplate-for-polyfill) لإتاحة المتصفّحات المطلوبة إلى أن تصبح هذه الميزة متاحة في Baseline.

استراتيجيات احتياطية

يمكنك استخدام polyfills مثل template-for-polyfill وhtml-setters-polyfill لمحاكاة واجهة برمجة التطبيقات للمتصفّحات غير المتوافقة.

أما المتصفحات التي لا تتوافق مع html-processing-instructions، فتحلّل <?marker> و<?start> و<?end> كتعليقات. لا يزال template-for-polyfill يتعرّف على هذه التعليقات كعلامات، لذا يجب الاحتفاظ ببنية تعليمات المعالجة نفسها لجميع المتصفحات. لا تُعِد كتابة العلامات كتعليقات أو عناصر HTML للمتصفّحات التي لا تتيح ذلك.