Skip to content

גלילה וירטואלית

למה זה קורה במנוע

השהיית הזנב של רשימות וירטואליות מבוססות DOM נובעת מהשרשרת: אירוע הגלילה חוזר לתהליכון הראשי, מפעיל ‏setState, אחריו diff ואחריו פריסה מחדש. ברגע שהתהליכון הראשי עסוק, פריימים נופלים.

‏doper מעביר את חישוב החלון לליבה: גלילה במצב יציב אינה קוראת למעטפת כלל. המעטפת רק מממשת את הטווח הנראה לפי חלון החימום שהליבה תכננה; אם הנתונים עדיין אינם מוכנים מצויר מציין מקום והוא מושלם בפריימים מאוחרים יותר.

שימוש

ts
createElement("virtualList", {
  width: 480,
  height: 640,
  itemCount: 1_000_000,
  estimatedItemHeight: 32,
  renderItem: (index: number) =>
    createElement("container", {
      width: 480,
      height: 32,
      children: createElement("text", { value: `שורה ${index}` }),
    }),
});

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

פרמטרים לכוונון

propהשפעה
baseOverscanViewportsטווח חימום סימטרי (בכפולות של חלון התצוגה)
velocityHorizonSecondsאופק היטל המהירות עבור חיזוי הכיוון
maximumAheadViewportsתקרת החימום בכיוון אחד
scrollX / scrollYמיקום גלילה תוכניתי (שולח ScrollTo רק כשהערך משתנה)

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

גלילה תוכניתית

ts
// שינוי ה-prop פולט mutation יחיד מסוג ScrollTo
root.render(createElement("virtualList", { scrollY: 500_000 * 32 /* ... */ }));

או באמצעות ממשק המניפולציה הישירה על ה-root, המיועד למחוות מותאמות:

ts
root.beginScroll(handle);
root.scrollBy(handle, 0, deltaY, elapsedMs);
root.endScroll(handle); // הליבה מעריכה את מהירות ההעפה

handle מגיע מקריאת ה-ref של הרכיב (NodeHandle).

גלגלת ומשטח מגע

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

קינון ועריכה

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

אמת מידה לביצועים

מדד הביצועים האוטומטי על מקבע קבוע (מיליון שורות, 20,000 פריימים) הוא חלק משער המיזוג. כיום P95/P99 של ההרצה החוזרת נמוכים ממיקרו-שנייה, ושלושים דקות של גלילה רצופה אינן מראות גידול זיכרון בלתי מבוקר.

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

בהדגמת הגלילה ב-Playground אפשר לראות מדדי פריים בזמן אמת.

מופץ ברישיון MIT