טעינת דפים מהירה יותר באמצעות זמן חשיבה של השרת עם רמזים מוקדמים

בדקו איך השרת יכול לשלוח לדפדפן רמזים לגבי משאבי משנה קריטיים.

מהם רמזים מוקדמים?

האתרים הפכו למתוחכמים יותר עם הזמן. לכן, אין זה יוצא דופן ששרת צריך לבצע עבודה שאינה טריוויאלית (לדוגמה, גישה למסדי נתונים או CDN שניגשים לשרת המקור) כדי להפיק את ה-HTML של הדף המבוקש. לצערנו, 'זמן החשיבה של השרת' גורם לזמן אחזור ארוך יותר לפני שהדפדפן יכול להתחיל לעבד את הדף. אכן, החיבור לא פעיל כל עוד נדרש לשרת להכין את התגובה.

תמונה שבה מוצג פער זמן של 200 אלפיות השנייה בין טעינת הדף לבין טעינת משאבים אחרים.
ללא רמזים מוקדמים: הכול חסום בשרת כדי לקבוע איך להגיב למשאב הראשי.

'טיפים מוקדמים' הוא קוד סטטוס HTTP (103 Early Hints) המשמש לשליחת תגובת HTTP ראשונית לפני תגובה סופית. כך שרת יכול לשלוח לדפדפן רמזים לגבי משאבי משנה קריטיים (לדוגמה: גיליונות סגנונות לדף, JavaScript קריטי) או מקורות שסביר להניח שהדף ישתמש בהם בזמן שהשרת עסוק ביצירת המשאב הראשי. הדפדפן יכול להשתמש ברמזים האלה כדי להפעיל חיבורים, ולבקש משאבי משנה בזמן ההמתנה למשאב הראשי. במילים אחרות, רמזים מוקדמים עוזרים לדפדפן לנצל את "זמן החשיבה על השרת" על ידי ביצוע עבודה מסוימת מראש, וכך להאיץ את טעינת הדפים.

תמונה שמראה איך התכונה 'טיפים מוקדמים' מאפשרת לדף לשלוח תשובה חלקית.
עם רמזים מוקדמים: השרת יכול לתת תגובה חלקית עם רמזים למשאבים בזמן שהוא קובע מה התשובה הסופית

במקרים מסוימים, השיפור בביצועים של Largest Contentful Paint (LCP) יכול לעבור מכמה מאות אלפיות השנייה, כפי שנמדד ב-Shopify וב-Cloudflare, ומהיר יותר אפילו לשנייה, כמו בדוגמה הזו לפני ואחרי ההשוואה:

השוואה בין שני אתרים.
לפני/אחרי השוואה של רמזים מוקדמים באתר בדיקה שבוצע באמצעות WebPageTest (Moto G4 - DSL)

איך משתמשים ברמזים מוקדמים

השלב הראשון שבו כדאי להשתמש ב'טיפים מוקדמים' הוא זיהוי דפי הנחיתה המובילים, כלומר הדפים שדרכם המשתמשים מתחילים בדרך כלל כשהם נכנסים לאתר. זה יכול להיות דף הבית, או דפי כרטיסי מוצר פופולריים אם הרבה משתמשים מגיעים מאתרים אחרים. הסיבה לכך שנקודות הכניסה האלה חשובות יותר מדפים אחרים היא שהתועלת של 'רמזים מוקדמים' יורדת ככל שהמשתמש מנווט באתר שלכם (כלומר, סביר יותר שלדפדפן יהיו כל משאבי המשנה הדרושים בניווט השני או השלישי שלאחר מכן). כמו כן, תמיד כדאי ליצור רושם ראשוני מצוין!

אחרי יצירת רשימת דפי הנחיתה המסודרת לפי עדיפויות, השלב הבא הוא לזהות אילו מקורות או משאבי משנה יהיו מועמדים טובים לקבל רמזים ל-preconnect או ל-preload. בדרך כלל אלו מקורות ומשאבי משנה שתורמים הכי הרבה למדדי משתמשים עיקריים, כמו LCP או First Contentful Paint. באופן מדויק יותר, חפש משאבי משנה חוסמים עיבוד, כגון JavaScript סינכרוני, גיליונות סגנונות ואפילו גופני אינטרנט. באופן דומה, כדאי לחפש מקורות שמארחים משאבי משנה שתורמים במידה רבה למדדי משתמשים מרכזיים.

כדאי גם לשים לב שאם המשאבים העיקריים שלך כבר משתמשים ב-preconnect או ב-preload, כדאי לקחת בחשבון את המקורות או המשאבים האלה בין המועמדים לקבלת רמזים מוקדמים. פרטים נוספים זמינים במאמר אופטימיזציה של LCP. עם זאת, העתקה בנימה של ההנחיות preconnect ו-preload מ-HTML ל'רמזים מוקדמים' עשויה להיות לא אופטימלית.

כשמשתמשים בטכנולוגיות האלה ב-HTML, בדרך כלל רצוי preconnect או preload משאבים שהסורק לטעינה מראש לא יגלה ב-HTML. לדוגמה, גופנים או תמונות רקע שבדרך כלל היו מתגלים מאוחר. ברמזים מוקדמים לא יהיה לך ה-HTML, ולכן כדאיpreconnect במקום זאת preconnect לדומיינים קריטיים או לpreload משאבים קריטיים שאחרת היו מתגלים בשלב מוקדם ב-HTML - לדוגמה, טעינה מראש main.css או app.js.בנוסף, לא כל הדפדפנים תומכים ב-preload עבור רמזים מוקדמים – ניתן לעיין בתמיכה בדפדפן.

השלב השני הוא לצמצם את הסיכון לשימוש ברמזים מוקדמים במשאבים או במקורות שכבר יצאו משימוש או שיפסיקו להשתמש במשאב הראשי. לדוגמה: יכול להיות שמשאבים שמתעדכנים בתדירות גבוהה וגרסאות שונות (לדוגמה, example.com/css/main.fa231e9c.css) לא האפשרות הטובה ביותר. לתשומת ליבך, הבעיה הזו לא ספציפית לרמזים מוקדמים, אלא על כל preload או preconnect בכל מקום שבו הם מופיעים. זהו סוג הפרטים שהכי מתאים לטיפול באוטומציה או יצירת תבניות (לדוגמה, תהליך ידני צפוי יותר להוביל לכתובות URL לא תואמות של גיבוב או גרסה בין preload לבין תג ה-HTML בפועל באמצעות המשאב).

כדוגמה, נבחן את התהליך הבא:

GET /main.html
Host: example.com
User-Agent: [....] Chrome/103.0.0.0 [...]

השרת צופה שיהיה צורך ב-main.abcd100.css, ומציע טעינה מראש באמצעות רמזים מוקדמים:

103 Early Hints
Link: </main.abcd100.css>; rel=preload; as=style
[...]

מספר רגעים לאחר מכן יוצג דף האינטרנט, כולל שירות ה-CSS המקושר. לצערנו, משאב ה-CSS הזה מתעדכן לעיתים קרובות, והמשאב הראשי כבר נמצא במרחק של חמש גרסאות קודמות (abcd105) ממשאב ה-CSS החזוי (abcd100).

200 OK
[...]
<HTML>
<head>
   <title>Example</title>
   <link rel="stylesheet" href="/main.abcd105.css">

באופן כללי, צריך לשאוף למשאבים ומקורות יציבים למדי, שברוב המקרים לא תלויים בהם בתוצאה של המשאב העיקרי. במקרה הצורך, כדאי לפצל את משאבי המפתח לשניים: חלק יציב שמיועד לשימוש עם רמזים מוקדמים, וחלק דינמי יותר שנותר לאחזור אחרי שהמשאב הראשי מתקבל על ידי הדפדפן:

<HTML>
<head>
   <title>Example</title>
   <link rel="stylesheet" href="/main.css">
   <link rel="stylesheet" href="/experimental.3eab3290.css">

לבסוף, בצד השרת, מחפשים את הבקשות העיקריות למשאבים שנשלחו על ידי דפדפנים שידועים כתומכים ברמזים מוקדמים, ומגיבים מיידית עם 103 רמזים מוקדמים. בתגובת 103, יש לכלול את הרמזים הרלוונטיים לחיבור מראש ולטעינה מראש. לאחר שהמשאב הראשי מוכן, ממשיכים לתגובה הרגילה (לדוגמה, 200 OK אם בוצע בהצלחה). לצורך תאימות לאחור, מומלץ לכלול בתגובה הסופית גם כותרות HTTP מסוג Link, אולי אפילו להוסיף להן משאבים קריטיים שהוכחו כחלק מיצירת המשאב הראשי (למשל, החלק הדינמי של משאב מפתח אם פעלתם לפי ההצעה "חלוקה לשניים"). כך זה ייראה:

GET /main.html
Host: example.com
User-Agent: [....] Chrome/103.0.0.0 [...]
103 Early Hints
Link: <https://fonts.google.com>; rel=preconnect
Link: </main.css>; rel=preload; as=style
Link: </common.js>; rel=preload; as=script

כמה רגעים לאחר מכן:

200 OK
Content-Length: 7531
Content-Type: text/html; charset=UTF-8
Content-encoding: br
Link: <https://fonts.google.com>; rel=preconnect
Link: </main.css>; rel=preload; as=style
Link: </common.js>; rel=preload; as=script
Link: </experimental.3eab3290.css>; rel=preload; as=style
<HTML>
<head>
   <title>Example</title>
   <link rel="stylesheet" href="/main.css">
   <link rel="stylesheet" href="/experimental.3eab3290.css">
   <script src="/common.js"></script>
   <link rel="preconnect" href="https://fonts.googleapis.com">

תמיכת דפדפן

למרות ש-103 רמזים מוקדמים נתמכים בכל הדפדפנים הנפוצים, ההנחיות שניתן לשלוח באמצעות רמז מוקדם משתנות בין דפדפנים:

תמיכה בחיבור מראש:

תמיכה בדפדפן

  • 103
  • 103
  • 120
  • 17

תמיכה בטעינה מראש:

תמיכה בדפדפן

  • 103
  • 103
  • 123
  • x

לכלי הפיתוח ל-Chrome יש גם תמיכה ב-103 רמזים מוקדמים.

תמיכה לשרתים

לפניכם סיכום מהיר של רמת התמיכה ב-Early Hints בקרב תוכנות השרת HTTP הנפוצות בתוכנת קוד פתוח:

הפעלת רמזים מוקדמים בדרך הקלה יותר

אם אתם משתמשים באחת מהפלטפורמות או ה-CDN הבאים, יכול להיות שלא תצטרכו להטמיע רמזים מוקדמים באופן ידני. אפשר לעיין במסמכי התיעוד אונליין של ספק הפתרון כדי לבדוק אם הוא תומך ברמזים מוקדמים, או לעיין ברשימה החלקית כאן:

איך למנוע בעיות ללקוחות שלא תומכים ברמזים מוקדמים

תגובות HTTP אינפורמטיביות בטווח 100 הן חלק מתקן ה-HTTP, אבל כמה לקוחות או בוטים ישנים יותר עשויים להיאבק בכך, כי לפני ההשקה של 103 רמזים מוקדמים, הם היו בשימוש רק לעיתים רחוקות לגלישה כללית באינטרנט.

פליטת 103 רמזים מוקדמים רק בתגובה ללקוחות ששולחים כותרת בקשת HTTP מסוג sec-fetch-mode: navigate אמורה להבטיח שרמזים כאלה יישלחו רק ללקוחות חדשים יותר שמבינים להמתין לתגובה הבאה. בנוסף, יש תמיכה ברמזים מוקדמים רק בבקשות ניווט (ראו מגבלות נוכחיות), כך יש יתרון נוסף: הימנעות משליחה מיותרת של הרמזים האלה בבקשות אחרות.

בנוסף, מומלץ לשלוח רמזים מוקדמים רק באמצעות חיבורי HTTP/2 או HTTP/3.

קו ביטול נעילה מתקדם

אם יישמתם את הרמזים המוקדמים באופן מלא על דפי הנחיתה המרכזיים שלכם ואתם מחפשים הזדמנויות נוספות, כדאי להשתמש בתבנית המתקדמת הבאה.

למבקרים שמופיעים בדף nth בקשה לדף כחלק מתהליך אופייני של משתמש, כדאי להתאים את התגובה של רמזים מוקדמים לתוכן שנמצא נמוך יותר ועומק בדף. במילים אחרות, השתמשו ברמזים מוקדמים במשאבים שבעדיפות נמוכה. זה יכול להישמע לא הגיוני, כי המלצנו להתמקד במקורות או במשאבי משנה בעדיפות גבוהה שחוסמים את העיבוד. עם זאת, עד שמבקר מנווט במשך זמן מה, סביר להניח שכבר יש בדפדפן שלו את כל המשאבים הקריטיים. לאחר מכן, כדאי להפנות את תשומת הלב למשאבים בעדיפות נמוכה. לדוגמה: כדאי להשתמש ב-EAP כדי לטעון תמונות של מוצרים, או להשתמש ב-JS/CSS נוספים שנחוצים רק לאינטראקציות פחות נפוצות של משתמשים.

מגבלות נוכחיות

אלה המגבלות של רמזים מוקדמים כפי שהם מוטמעים ב-Chrome:

  • זמין רק לבקשות ניווט (כלומר, המשאב הראשי של המסמך ברמה העליונה).
  • יש תמיכה רק ב-preconnect וב-preload (כלומר, אין תמיכה ב-prefetch).
  • רמז מוקדם ואחריו הפניה מחדש ממקורות שונים בתגובה הסופית יגרום לכך ש-Chrome ישמיט את המשאבים והחיבורים שהוא השיג באמצעות רמזים מוקדמים.

לדפדפנים אחרים יש מגבלות דומות, וחלקם מגבילים עוד יותר 103 רמזים מוקדמים ל-preconnect בלבד.

מה השלב הבא?

בהתאם לתחומי העניין בקהילה, אנחנו עשויים להרחיב את ההטמעה של 'רמזים מוקדמים' באמצעות היכולות הבאות:

  • רמזים מוקדמים נשלחים בבקשות למשאבי משנה.
  • רמזים מוקדמים נשלחו בבקשות משאבים ראשיים של iframe.
  • תמיכה בשליפה מראש (prefetch) ברמזים מוקדמים.

נשמח לקבל משוב לגבי ההיבטים שכדאי לתת להם עדיפות, ואיך לשפר עוד יותר את הרמזים המוקדמים.

הקשר ל-H2/Push

אם אתם מכירים את התכונה HTTP2/Push שהוצאה משימוש, אולי תרצו להבין מה ההבדל בין רמזים מוקדמים. למרות שרמזים מוקדמים דורשים שינוי הלוך ושוב כדי שהדפדפן יתחיל לאחזר משאבי משנה קריטיים, באמצעות HTTP2/Push, השרת יוכל להתחיל לדחוף משאבי משנה לצד התגובה. זה נשמע מדהים, אבל הדבר גרם לחסרונות מבניים מרכזיים: עם HTTP2/Push היה קשה מאוד להימנע מדחיפת משאבי משנה שכבר היו לדפדפן. השפעת "דחיפת-יתר" זו הובילה לשימוש פחות יעיל ברוחב הפס של הרשת, וכתוצאה מכך פגעה באופן משמעותי ביתרונות הביצועים. באופן כללי, הנתונים של Chrome הראו ש-HTTP2/Push היה למעשה מדד נטו של ביצועים באינטרנט.

לעומת זאת, לאפליקציה 'טיפים מוקדמים' יש ביצועים טובים יותר בפועל כי הם משלבים את היכולת לשלוח תגובה ראשונית עם רמזים שעוזרים לדפדפן לאחזר את מה שהוא צריך באמת, או להתחבר אליו. למרות ש-EAP לא מכסה את כל התרחישים לדוגמה ש-HTTP2/Push יכול לטפל בהם, אנחנו מאמינים ש-EAP הוא פתרון מעשי יותר לזירוז הניווט.

תמונה ממוזערת של פייר באמין.