התערבות ב-document.write()

האם ראית לאחרונה אזהרה כמו זו ב-Developer Console ב-Chrome ותהית מה זה?

(index):34 A Parser-blocking, cross-origin script,
https://paul.kinlan.me/ad-inject.js, is invoked via document.write().
This may be blocked by the browser if the device has poor network connectivity.

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

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

document.write('<script src="https://example.com/ad-inject.js"></script>');

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

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

אספנו נתונים מניסוי שטח בן 28 ימים אצל 1% מהמשתמשים היציבים של Chrome, המוגבל למשתמשים בחיבורי 2G. ראינו ש-7.6% מכל טעינות הדפים ב-2G כללו לפחות סקריפט אחד לחסימת מנתח אתרים, שהוכנס דרך document.write() למסמך ברמה העליונה. בעקבות חסימת הטעינה של הסקריפטים האלה, ביצענו את השיפורים הבאים בטעינות האלה:

  • עלייה של 10% בטעינות דפים שמגיעות להצגת תוכן ראשוני (FCP) (אישור חזותי למשתמש שהדף נטען בפועל), 25% יותר טעינות דפים שמגיעים למצב ניתוח מלא ו-10% פחות טעינות מחדש שמצביעות על ירידה בתסכול המשתמשים.
  • ירידה של 21% בזמן הממוצע (מהיר יותר משנייה) עד הצגת תוכן ראשוני (FCP)
  • הפחתה של 38% מהזמן הממוצע לניתוח דף, שמייצגת שיפור של כמעט שש שניות ומפחיתה באופן משמעותי את הזמן שנדרש להצגת הפרטים שחשובים למשתמש.

תוך התחשבות בנתונים האלה, Chrome, החל מגרסה 55, מתערב בשם כל המשתמשים כשאנחנו מזהים את הדפוס הלא תקין הזה על ידי שינוי האופן שבו document.write() מטופל ב-Chrome (ראו סטטוס Chrome). באופן ספציפי, Chrome לא יפעיל את רכיבי <script> שהוחדרו דרך document.write() כאשר כל התנאים הבאים מתקיימים:

  1. החיבור של המשתמש איטי, במיוחד כאשר הוא פועל ב-2G. (בעתיד, ייתכן שהשינוי יורחב למשתמשים אחרים בחיבורים איטיים, כמו 3G איטי או Wi-Fi איטי).
  2. document.write() נמצא במסמך ברמה עליונה. ההתערבות לא חלה על סקריפטים של document.write בתוך iframes, כי הם לא חוסמים את העיבוד של הדף הראשי.
  3. הסקריפט ב-document.write() חוסם מנתח. סקריפטים עם המאפיינים 'async' או 'defer' עדיין יופעלו.
  4. הסקריפט לא מתארח באותו אתר. במילים אחרות, Chrome לא יתערב בסקריפטים עם eTLD+1 תואם (למשל, סקריפט שמתארח ב-js.example.org שהוכנס ב-www.example.org).
  5. הסקריפט לא נמצא כבר במטמון ה-HTTP של הדפדפן. הסקריפטים במטמון לא יגרמו לעיכוב ברשת, והם ימשיכו לפעול.
  6. הבקשה לדף אינה טעינה מחדש. Chrome לא יתערב אם המשתמש הפעיל טעינה מחדש ויפעיל את הדף כרגיל.

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

כיצד ניתן לתקן זאת?

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

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

אם הספק שלכם לא תומך באפשרות לטעון סקריפטים לדף שלכם באופן אסינכרוני, מומלץ ליצור איתם קשר ולהודיע לנו איך הם יושפעו.

אם הספק נותן לך קטע קוד שכולל את document.write(), יכול להיות שאפשר להוסיף את המאפיין async לרכיב הסקריפט, או להוסיף את רכיבי הסקריפט באמצעות DOM API כמו document.appendChild() או parentNode.insertBefore().

איך מזהים מתי האתר מושפע?

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

זיהוי כשמשתמש נמצא ב-2G

כדי להבין את ההשפעה הפוטנציאלית של השינוי הזה, קודם כל צריך להבין כמה מהמשתמשים יהיו ב-2G. תוכלו לזהות את סוג הרשת והמהירות הנוכחיים של המשתמש באמצעות Network Information API שזמין ב-Chrome, ולאחר מכן לשלוח התראה למערכות של Analytics או Real User Metrics (RUM).

if(navigator.connection &&
    navigator.connection.type === 'cellular' &&
    navigator.connection.downlinkMax <= 0.115) {
    // Notify your service to indicate that you might be affected by this restriction.
}

אזהרות לגבי התראות בכלי הפיתוח ל-Chrome

החל מגרסה Chrome 53, הכלי DevTools שולח אזהרות על הצהרות document.write() בעייתיות. באופן ספציפי, אם בקשת document.write() עומדת בקריטריונים 2 עד 5 (Chrome מתעלם מקריטריוני החיבור בעת שליחת האזהרה הזו), האזהרה תיראה בערך כך:

אזהרה לגבי כתיבת מסמך.

זה מעולה להציג אזהרות בכלי הפיתוח ל-Chrome, אבל איך מזהים את האזהרות בקנה מידה נרחב? אפשר לבדוק אם יש כותרות HTTP שנשלחות לשרת שלכם במהלך ההתערבות.

בדוק את כותרות ה-HTTP במשאב הסקריפט

כשחוסמים סקריפט שהוכנס דרך document.write, Chrome שולח את הכותרת הבאה למשאב המבוקש:

Intervention: <https://shorturl/relevant/spec>;

אם סקריפט שנוסף דרך document.write נמצא ויכול להיות שנחסם בנסיבות שונות, Chrome עשוי לשלוח:

Intervention: <https://shorturl/relevant/spec>; level="warning"

כותרת ההתערבות תישלח כחלק מבקשת ה-GET לסקריפט (באופן אסינכרוני במקרה של התערבות בפועל).

מה צופן העתיד?

התוכנית הראשונית היא לבצע את ההתערבות הזו כשהמערכת מזהה עמידה בקריטריונים. התחלנו להציג אזהרה בלבד ב-Play Console ב-Chrome 53. (גרסת הבטא הייתה ביולי 2016. אנחנו צופים שהגרסה היציבה תהיה זמינה לכל המשתמשים בספטמבר 2016).

אנחנו נתערב כדי לחסום סקריפטים שהוחדרו למשתמשי 2G באופן זמני החל מ-Chrome 54, שלפי ההערכות הוא יהיה בגרסה יציבה לכל המשתמשים מאמצע אוקטובר 2016. לעדכונים נוספים, עיינו בערך של סטטוס Chrome.

עם הזמן, אנחנו מעוניינים להתערב כאשר למשתמש כלשהו יש חיבור איטי (כלומר, 3G או Wi-Fi איטי). פועלים לפי ערך הסטטוס הזה של Chrome.

רוצה לדעת עוד?

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