רשימות ארוכות בממשק - למה Virtualization חוסך לכם ביצועים¶
תארו לעצמכם טבלה עם עשרת אלפים שורות, או רשימת התראות שלא נגמרת. אם תרנדרו את כולן בבת אחת, הדפדפן ייצור עשרת אלפים אלמנטים ב-DOM, גם אם המשתמש רואה בפועל עשרים שורות על המסך בכל רגע נתון. זו אחת הטעויות הנפוצות ביותר בבניית ממשקים עם הרבה נתונים, וגם אחת שקל יחסית לתקן ברגע שמבינים את העיקרון שמאחורי הפתרון.
הבעיה - למה DOM גדול איטי¶
כל אלמנט ב-DOM עולה משהו. הדפדפן צריך לחשב עבורו סטייל, למקם אותו בפריסה, ולצייר אותו על המסך. כשיש רק כמה עשרות אלמנטים זה לא מורגש בכלל, אבל כשמדובר באלפי שורות, כל פעולה שנוגעת ברשימה, כמו גלילה, סינון, או אפילו שינוי גודל חלון, יכולה לגרום לדפדפן לחשב מחדש פריסה של אלמנטים שהמשתמש בכלל לא רואה. זו עבודה מבוזבזת: אתם משלמים מחיר ביצועים על משהו שאין לו שום ערך ויזואלי כרגע.
הפתרון - לרנדר רק את מה שנראה¶
וירטואליזציה, או windowing, פותרת את זה בגישה פשוטה: במקום לרנדר את כל הרשימה, מרנדרים רק את הפריטים שנמצאים כרגע בטווח הראייה, פלוס אולי כמה פריטים נוספים מעל ומתחת כרגע "חוצץ", כדי שהגלילה תיראה חלקה ולא תיתקל ברווח ריק. שאר הרשימה פשוט לא קיימת ב-DOM בכלל, אלא רק בנתונים שיש לכם באפליקציה.
איך זה עובד בפועל: הרכיב שאחראי על הרשימה יודע את הגובה הכולל של כל הפריטים, בונה שטח ריק בגודל המתאים כדי שהגלילה תתנהג נכון, ובזמן שהמשתמש גולל, הוא מחליף את הפריטים המוצגים בהתאם למיקום הגלילה. מבחינת המשתמש זה נראה כמו רשימה רגילה שגוללים בה, אבל בפועל הדפדפן מנהל בכל רגע נתון רק שבריר קטן מהאלמנטים.
[ שטח ריק עליון בגובה הפריטים שגללנו מעבר להם ]
[ פריט שגלוי כרגע ]
[ פריט שגלוי כרגע ]
[ פריט שגלוי כרגע ]
[ שטח ריק תחתון בגובה שאר הפריטים שעוד לא הגענו אליהם ]
זה מסביר גם למה וירטואליזציה יכולה להסתבך כשגובה הפריטים משתנה ולא קבוע: הרכיב צריך דרך לדעת או להעריך כמה מקום כל פריט תופס, כדי לחשב נכון את מיקום הגלילה ואת גודל השטח הריק. עם פריטים בגובה קבוע זה חישוב פשוט, עם פריטים בגובה משתנה זה דורש מנגנון מדידה נוסף.
גלילה אינסופית - דפוס קרוב אבל שונה¶
יש כאן גם מושג שקשור אבל לא זהה: גלילה אינסופית, שבה עוד פריטים נטענים מהשרת ככל שהמשתמש מתקרב לתחתית הרשימה. שימו לב שאלה שני דברים נפרדים. גלילה אינסופית פותרת בעיה של כמה נתונים אתם מביאים מהשרת ומתי, בעוד וירטואליזציה פותרת בעיה של כמה DOM אתם בונים מהנתונים שכבר יש לכם בצד הלקוח. אפשר להשתמש בכל אחת בנפרד, ואפשר גם לשלב ביניהן: להביא נתונים בהדרגה עם גלילה אינסופית, ובמקביל לרנדר רק את מה שנראה מתוכם עם וירטואליזציה, למקרה שכמות הנתונים שכבר נטענה גדלה משמעותית.
מתי בכלל צריך את זה¶
לא כל רשימה זקוקה לוירטואליזציה. אם מדובר בעשרות פריטים, הרינדור הרגיל של הדפדפן מתמודד איתו בלי בעיה, והוספת וירטואליזציה רק תוסיף מורכבות מיותרת לקוד. השאלה שכדאי לשאול היא כמה פריטים אתם מצפים שיהיו ברשימה במקרה השימוש הריאלי, לא רק בבדיקות. כשמדובר בטבלאות נתונים גדולות, פידים של רשתות חברתיות, או רשימות לוגים, זה בדיוק המקרה שבו וירטואליזציה עושה הבדל. קיימות ספריות מוכנות שמטפלות בחישובים האלה עבורכם, כך שברוב המקרים לא צריך לממש את המנגנון מאפס.
בקורס צד לקוח עוברים על איך בונים רכיבי רשימה וטבלה בצורה שמתחשבת בביצועים כבר מהשלב הראשוני של העיצוב שלהם.
לסיכום¶
וירטואליזציה היא דוגמה טובה לעיקרון רחב יותר: לא צריך לרנדר משהו שהמשתמש לא רואה. ברגע שהרשימות שלכם גדלות, שווה לבדוק אם אתם משלמים מחיר ביצועים על אלמנטים שממילא נמצאים מחוץ למסך.
אם התלבטתם בין וירטואליזציה לגלילה אינסופית בפרויקט שלכם, אשמח לשמוע איך זה התנהל אצלכם.