גלילה מהירה של הגלגלים כברירת מחדל

Sahel Sharify
Sahel Sharify

כדי לשפר את הביצועים של wheel בגלילה או בהגדלת התצוגה, מפתחים מומלצים לרשום פונקציות event listener של wheel ו-mousewheel כפסיביות על ידי העברת האפשרות {passive: true} אל addEventListener(). רישום של פונקציות ה-event listener כפונקציות פסיביות מאפשר לדפדפן לדעת שפונקציות ה-listener של הגלגל לא יקראו ל-preventDefault(), ולדפדפן לבצע בבטחה גלילה ושינוי מרחק התצוגה בלי לחסום את ה-listeners.

הבעיה היא שברוב המקרים, רכיבי המעקב אחרי אירועי גלילה הם פסיביים מבחינה מושגית (לא קוראים ל-preventDefault()), אבל הם לא מצוינים ככאלה באופן מפורש, ולכן הדפדפן צריך להמתין לסיום הטיפול באירוע ב-JS לפני שהוא מתחיל לגלול או להתקרב, למרות שהמתנה לא נדרשת. ב-Chrome 56, תיקנו את הבעיה הזו עבור touchstart ו-touchmove, והשינוי הזה אומץ מאוחר יותר גם ב-Safari וגם ב-Firefox. כפי שאפשר לראות בסרטון ההדגמה שיצרנו באותו זמן, השארת ההתנהגות כפי שהיא גרמה לעיכוב ניכר בתגובה לגלילה. עכשיו, בגרסה 73 של Chrome, החלנו את אותה התערבות על אירועים מסוג wheel ו-mousewheel.

ההתערבות

המטרה של השינוי הזה היא לקצר את הזמן שלוקח לעדכן את המסך אחרי שהמשתמש מתחיל לגלול באמצעות הגלגל או משטח המגע, בלי שהמפתחים יצטרכו לשנות את הקוד. לפי המדדים שלנו, 75% ממאזני האירועים של wheel ו-mousewheel שנרשמו ביעדים ברמה הבסיסית (חלון, מסמך או גוף) לא מציינים ערכים לאפשרות הפסיבית, ויותר מ-98% ממאזני האירועים האלה לא קוראים ל-preventDefault(). ב-Chrome 73, אנחנו משנים את המאזינים wheel ו-mousewheel שנרשמים ביעדים ברמה הבסיסית (חלון, מסמך או גוף) כך שיהיו פסיביים כברירת מחדל. המשמעות היא שפונקציית event listener כמו:

window.addEventListener("wheel", func);

הופך להיות שווה ערך ל-:

window.addEventListener("wheel", func, {passive: true});

קריאה ל-preventDefault() בתוך המאזין תתעלם עם האזהרה הבאה ב-DevTools:

[Intervention] Unable to preventDefault inside passive event listener due
to target being treated as passive. See https://www.chromestatus.com/features/6662647093133312

שגיאות והנחיות

ברוב המקרים לא תבחינו בשינוי. רק במקרים נדירים (פחות מ-0.3% מהדפים לפי המדדים שלנו), יכול להיות שתתבצע גלילה או שינוי מרחק התצוגה לא מכוונים בגלל שהקריאה ל-preventDefault() מתעלמת בתוך המאזינים שנחשבים כפסיביים כברירת מחדל. האפליקציה יכולה לקבוע אם היא נתקלת בבעיה הזו בשטח על ידי בדיקה אם לקריאה ל-preventDefault() הייתה השפעה כלשהי דרך המאפיין defaultPrevented. התיקון במקרים הרלוונטיים קל יחסית: מעבירים את הערך {passive: false} אל addEventListener() כדי לשנות את התנהגות ברירת המחדל ולשמור את מאזין האירועים כחוסם.