תוספים ל-Chrome: הרחבת ממשק ה-API לתמיכה בניווט מיידי

Dave Tapuska
Dave Tapuska

אמ;לק: Extensions API עודכן כדי לתמוך במטמון לדף הקודם/הבא ובטעינה מראש של ניווטים. פרטים נוספים מופיעים בהמשך.

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

הסבר על סוגי הדפים

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

פינוי הדף הפעיל
הסרת הדף הפעיל.

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

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

סוגי דפים
סוגי דפים.

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

מה משתנה מבחינת מפתחי התוספים?

FrameId == 0

ב-Chromium, אנחנו מתייחסים למסגרת העליונה או הראשית כאל המסגרת החיצונית ביותר.

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

מחזור החיים של מסגרות לעומת מסמכים

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

אירועי ניווט באתר

אירועים במרחב השמות chrome.webNavigation יכולים להתרחש כמה פעמים באותו דף, בהתאם למחזור החיים שבו הוא נמצא. עיינו בקטעים "איך אפשר לדעת באיזה מחזור חיים של הדף?" ו"איך אפשר לקבוע מתי דף עובר?".

איך אפשר לדעת באיזה שלב מחזור חיים הדף נמצא?

הסוג DocumentLifecycle התווסף למספר ממשקי API של תוספים שבהם הסוג frameId היה זמין בעבר. אם הסוג DocumentLifecycle מופיע באירוע (למשל onCommitted), הערך שלו הוא המצב שבו האירוע נוצר. תמיד אפשר לשלוח שאילתות לגבי מידע מהשיטות WebNavigation getFrame() ו-getAllFrames(), אבל תמיד עדיף להשתמש בערך מהאירוע. אם משתמשים באחת משתי השיטות, חשוב לשים לב שמצב הפריים עשוי להשתנות בין מועד יצירת האירוע לבין מועד סיום ההבטחה החוזרת בשתי השיטות.

השדה DocumentLifecycle כולל את הערכים הבאים:

  • "prerender": לא מוצג כרגע למשתמש, אבל ייתכן שהוא יוצג לו.
  • "active": מוצגת כרגע למשתמש.
  • "cached": מאוחסן במטמון לדף הקודם/הבא.
  • "pending_deletion": המסמך מושמד.

איך אפשר לקבוע אם מסגרת מסוימת היא המסגרת החיצונית ביותר?

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

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

  • "outermost_frame": בדרך כלל מכונה המסגרת העליונה. שימו לב שיש ערכים מרובים של כל אחד מהם. לדוגמה, אם יש לכם דפים שעברו עיבוד מראש ונשמרו במטמון, לכל אחד מהם יש מסגרת חיצונית שאפשר לכנות אותה המסגרת העליונה.
  • "fenced_frame": שמור לשימוש עתידי.
  • "sub_frame": בדרך כלל iframe.

אפשר לשלב את DocumentLifecycle עם FrameType ולקבוע אם מסגרת מסוימת היא המסגרת החיצונית הפעילה. לדוגמה: tab.documentLifecycle === “active” && frameType === “outermost_frame”

איך אפשר לפתור בעיות בנושא זמן שימוש במסגרות?

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

כדי לפתור את הבעיה השתמשנו גם ב-documentId (וגם ב-parentDocumentId). ה-method webNavigation.getFrame() הופכת את frameId לאופציונלי אם מספקים documentId. הערך של documentId ישתנה בכל פעם שעוברים לפריים אחר.

איך אפשר לקבוע מתי מתבצע מעבר בין דפים?

יש אותות מפורשים שאפשר להשתמש בהם כדי לקבוע מתי דף עובר בין מצבים.

בואו נבחן את האירועים של WebNavigation.

בפעם הראשונה שתבצעו ניווט בדף כלשהו, יוצגו לכם ארבעה אירועים בסדר שמופיע בהמשך. חשוב לזכור שארבעת האירועים האלה יכולים להתרחש כאשר המצב DocumentLifecycle הוא "prerender" או "active".

onBeforeNavigate
onCommitted
onDOMContentLoaded
onCompleted

אפשר לראות את זה בתרשים שלמטה, שבו documentId משתנה ל-"xyz" כשהדף שעבר עיבוד מראש הופך לדף הפעיל.

השדה documentId משתנה כשהדף שעבר עיבוד מראש הופך לדף הפעיל
הערך של documentId משתנה כשהדף שעבר עיבוד מראש הופך לדף הפעיל.

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

onBeforeNavigate
onCommitted
onCompleted

הערך של documentId יישאר זהה לזה שבאירועים המקוריים. הדוגמה שלמעלה ממחישה את המצב הזה כשהביטוי documentId == xyz מופעל. חשוב לזכור שאותם אירועי ניווט מופעלים, מלבד האירוע onDOMContentLoaded, כי הדף כבר נטען.

אם יש לכם הערות או שאלות, אתם מוזמנים לשאול בקבוצת chromium-extensions.