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

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

קנג'י בהו
קנג'י בהו
בארי פולארד
בארי פולארד

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

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

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

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

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

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

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

שימוש ברמזים מוקדמים

לפני שניכנס לעומק הנושא, חשוב לדעת ש'רמזים מוקדמים' לא שימושיים אם השרת יכול לשלוח מיד 200 תשובות (או תשובות סופיות אחרות). במקום זאת, מומלץ להשתמש בשיטה הרגילה link rel=preload או link rel=preconnect בתגובה הראשית (כותרת הקישור של rel HTTP), או בתגובה הראשית (רכיבי <link>), במצבים כאלה. במקרים שבהם לשרת נדרש קצת זמן כדי ליצור את התגובה העיקרית, המשיכו לקרוא!

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

עכשיו, לאחר שהרשימה הזו של דפי נחיתה מוגדרת לפי העדיפות שלכם, השלב הבא הוא זיהוי המקורות או משאבי המשנה שיהיו מועמדים טובים לרמזים של קישור מראש או של טעינה מראש, כאומדן ראשון. בדרך כלל מדובר במקורות ובמשאבי משנה שתורמים הכי הרבה למדדי משתמשים מרכזיים, כמו Largest Contentful Paint (LCP) או הצגת תוכן ראשוני (FCP). באופן מדויק יותר, חפש משאבי משנה חוסמי עיבוד, כמו JavaScript סינכרוני, גיליונות סגנונות ואפילו גופני אינטרנט. באופן דומה, כדאי לחפש מקורות שמארחים משאבי משנה שתורמים באופן משמעותי למדדי משתמשים מרכזיים. הערה: אם המשאבים העיקריים שלך כבר משתמשים ב-<link rel=preconnect> או ב-<link rel=preload>, כדאי לשקול את המקורות או המשאבים האלה בין המועמדים לקבלת 'רמזים מוקדמים'. פרטים נוספים זמינים במאמר הזה.

השלב השני הוא לצמצם את הסיכון לשימוש ברמזים מוקדמים במשאבים או במקורות שעשויים להיות מיושנים, או לא בשימוש יותר במשאב הראשי. למשל, ייתכן שמשאבים שמתעדכנים בתדירות גבוהה וגרסאות חדשות יותר (למשל example.com/css/main.fa231e9c.css) לא הם האפשרות הטובה ביותר. חשוב לשים לב שהבעיה לא קשורה ספציפית ל'רמזים מוקדמים', אלא על כל קישור rel=preload או rel=preconnect, בכל מקום שבו הם מופיעים. זהו סוג הפרטים המתאים ביותר לטיפול באוטומציה או יצירת תבניות (לדוגמה, תהליך ידני צפוי יותר להוביל לחוסר התאמה בכתובות URL של גיבוב או של גרסה בין link rel=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 Early Hints נתמך בכל הדפדפנים העיקריים, ההנחיות שניתן לשלוח ב-Hint Hint משתנות בין הדפדפן:

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

תמיכה בדפדפן

  • 103
  • 103
  • 120
  • 17

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

תמיכה בדפדפן

  • 103
  • 103
  • x

תמיכה לשרתים

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

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

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

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

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

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

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

דפוס מתקדם

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

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

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

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

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

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

מה השלב הבא?

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

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

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

קשר ל-H2/דחיפה

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

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

תמונה ממוזערת מאת Pierre Bamin.