סטרימינג של HTML לא לפי הסדר (OOO)

העברה בסטרימינג של HTML שלא לפי הסדר (OOO) (נקראת גם "עדכונים חלקיים בהצהרה") היא חלופה לעיבוד הליניארי המסורתי של HTML "מלמעלה למטה". היא מאפשרת למפתחים להגדיר פלייסהולדרים בשלב מוקדם יותר במסמך, ו "לתקן" אותם באמצעות תוכן שמגיע מאוחר יותר באותו סטרימינג ברשת, או באמצעות ממשקי API חדשים של JavaScript לסטרימינג.

סקירה כללית קצרה

התכונה הזו מורכבת משני מנגנונים עיקריים:

  1. תיקון הצהרתי (מבוסס-HTML): משתמש בהוראות עיבוד חדשות (<?marker>, <?start>, <?end>) וב-<template for> כדי להחליף תוכן ב-DOM בזמן שהוא מועבר בסטרימינג מהשרת.
  2. הגדרה וסטרימינג אימפרטיביים (מבוססי JS): חבילה של שיטות חדשות (למשל, streamHTML(), setHTMLUnsafe()) שמאפשרות להגדיר HTML או להעביר סטרימינג קריא ישירות לאלמנטים של DOM עם ביצועים מקוריים והרצת סקריפטים אופציונלית.

שיטות מומלצות

  • תעדוף תוכן בחלק העליון והקבוע של המסך: קודם כל, צריך להעביר בסטרימינג את ממשק המשתמש החיוני (כותרת, תמונה ראשית, ניווט ראשי, תוכן ראשי). השתמשו בפלייסהולדרים לרכיבים "יקרים" או בעלי עדיפות נמוכה יותר, כמו תגובות, מודעות או תוכן קשור.
  • הטמעת מצבי טעינה מקוריים: משתמשים בסימונים <?start> ו-<?end> כדי לעטוף תוכן חלופי. הדפדפן מחליף באופן אוטומטי את כל מה שבין הסמנים האלה כשמגיע ה-<template for> המתאים.
  • צמצום מדד היציבות החזותית (CLS): תמיד צריך לספק מידות יציבות לפלייסהולדרים. אם גודל התוכן הסופי לא ידוע, השתמשו במסכי שלד או ב-CSS aspect-ratio כדי לשמור מקום ולמנוע שינויים פתאומיים.
  • נגישות וניהול המיקוד: חשוב לזכור שעדכונים לא מסודרים עלולים לבלבל משתמשים שנעזרים בקורא מסך. צריך להשתמש באזורי 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, והדפדפן יעבד אותו בהדרגה ככל שהחלקים יגיעו.

דוגמה: סטרימינג של תגובת אחזור

אתם יכולים להעביר תגובות של שליפה ישירות ל-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): אפשר להעביר בסטרימינג מעברים גדולים של ממשק המשתמש באפליקציות SPA באמצעות streamHTML() במקום להמתין למטען ייעודי (payload) מלא של JSON ולבנייה ידנית של DOM.

דפוסי אנטי-תבנית ואזהרות (מה לא לעשות)

  • אל תשתמשו בסטרימינג מחוץ למשרד לכל דבר. פיצול יתר של דף יכול להגביר את המורכבות של הסטרימינג ולעכב את הצגת התוכן אם הדפדפן מקדיש יותר מדי זמן לתיקון צמתים קטנים.
  • אל תתעלמו מסוגים מהימנים. כשמשתמשים בשיטות *Unsafe בסביבות שבהן נאכפים סוגים מהימנים, צריך לוודא שמועבר אובייקט מדיניות שעבר הסרת תוכן זדוני או רגיש, אם נדרש.
  • אל תניחו שהסקריפטים יופעלו בסדר מסוים. סקריפטים בתוך <template for> יופעלו ברגע שהם יתווספו למסמך. אל תסתמכו על כך שהן יתבצעו ברצף מסוים ביחס לתבניות מושהות אחרות.
  • אל תשתמשו בה בלי אסטרטגיית polyfill. כדי לתמוך בדפדפנים הנדרשים עד שהתכונה הזו תהפוך ל-Baseline, צריך לוודא שיש לכם חלופה או להשתמש ב-polyfill‏ (html-setters-polyfill ו-template-for-polyfill).

אסטרטגיות חלופיות

אפשר להשתמש ב-polyfills כמו template-for-polyfill ו-html-setters-polyfill כדי לדמות את ממשק ה-API בדפדפנים שלא תומכים בו.

דפדפנים שלא תומכים ב-html-processing-instructions מנתחים את <?marker>, <?start> ו-<?end> כתגובות. ‫template-for-polyfill עדיין מזהה את ההערות האלה כסמנים, לכן צריך להשתמש באותו תחביר של הוראות עיבוד בכל הדפדפנים. אל תשכתבו את הסמנים כהערות או כרכיבים ב-HTML בשביל דפדפנים שלא תומכים בהם.