تعقيدات تمرير لا نهائي

النصّ المختصر (TL;DR): إعادة استخدام عناصر DOM وإزالة العناصر البعيدة عن إطار العرض. استخدِم العناصر النائبة لمراعاة البيانات المتأخرة. إليك الإصدار التجريبي والرمز للعدد اللانهائي شريط التمرير.

تظهر شريط تمرير لا نهائي في جميع أنحاء الإنترنت. قائمة الفنانين في Google Music هي الأول، المخطط الزمني في Facebook هو واحد، وخلاصة البث المباشر على Twitter أيضًا. إِنْتَ انتقِل للأسفل وقبل الوصول إلى الأسفل، سيظهر محتوى جديد بشكل سحري تبدو من العدم. وهي تجربة سلسة للمستخدمين ومن السهل يُرجى الاطّلاع على طلب إعادة النظر.

ومع ذلك، فإنّ التحدّي التقني وراء لعبة التمرير اللا نهائي أصعب منها. يبدو. نطاق المشكلات التي تواجهها عندما تريد القيام بالأشياء الصحيحةTM ضخمة. يبدأ بأشياء بسيطة مثل أن تصبح الروابط في التذييل لا يمكن الوصول إليه عمليًا لأن المحتوى يستبعد التذييل. لكن تصبح المشكلات أكثر صعوبة. كيف تتعامل مع حدث تغيير الحجم عندما يحول شخص ما من الوضع العمودي إلى الوضع الأفقي، أو كيف يمكن منع انصهار الهاتف من العمل إلى التوقف المؤلم عندما تصبح القائمة طويلة جدًا؟

The rightthTM

رأينا أنّ هذا القرار كان سببًا كافيًا للتوصّل إلى مرجع. تظهر طريقة لمعالجة كل هذه المشكلات بطريقة قابلة لإعادة الاستخدام بينما والحفاظ على معايير الأداء.

سنستخدم 3 أساليب لتحقيق هدفنا، وهي إعادة تدوير نموذج العناصر في المستند (DOM) وشواهد القبور وارتساء التمرير.

ستكون حالتك التجريبية هي نافذة دردشة تشبه دردشة الفيديو الجماعية حيث يمكننا التمرير عبر الرسائل. أول ما نحتاج إليه هو توفير مصدر غير محدود للمحادثات. الرسائل. من الناحية الفنية، لا تتوفر أي من عناصر التمرير اللانهائية غير محدودة، ولكن مع كمية البيانات المتاحة لضخها في هذه لشريط التمرير قد يكون كذلك. ولتبسيط الأمر، سنقوم فقط بترميز مجموعة من رسائل الدردشة واختر الرسالة والمؤلف ومرفق الصور من وقت لآخر من عشوائيًا مع القليل من التأخير الاصطناعي لتعمل بشكل أشبه شبكة حقيقية.

لقطة شاشة لتطبيق Chat

إعادة تدوير DOM

إعادة تدوير DOM هي تقنية غير مُستخدَمة بشكل كافٍ لإبقاء عدد عُقد DOM منخفضًا. تشير رسالة الأشكال البيانية هي استخدام عناصر DOM التي سبق إنشاؤها خارج الشاشة إنشاء أهداف جديدة. نعترف بأنّ عُقد DOM نفسها رخيصة، ولكنّها غير ليس مجانيًا، حيث يضيف كل منها تكلفة إضافية في الذاكرة والتخطيط والأسلوب والطلاء. وستكون الأجهزة المنخفضة السرعة أبطأ بشكل ملحوظ إذا لم تكن غير قابلة للاستخدام تمامًا إذا حجم كائن (DOM) لموقع الويب كبير جدًا بحيث لا يمكن إدارته. ضع في اعتبارك أيضًا أن كل ترحيل وإعادة تطبيق أنماطك - وهي عملية يتم تشغيلها كلما تم تطبيق تتم إضافتها أو إزالتها من عُقدة، يزداد سعرها عند زيادة حجم العناصر في المستند (DOM). تعني إعادة تدوير عُقد DOM أننا سنحتفظ بالعدد الإجمالي لـ DOM أقل بكثير، مما يجعل جميع هذه العمليات أسرع.

العقبة الأولى هي التمرير نفسه. نظرًا لأن لدينا مجموعة فرعية صغيرة فقط جميع العناصر المتاحة في نموذج العناصر في المستند (DOM) في أي وقت، نحتاج إلى إيجاد طريقة أخرى لجعل شريط التمرير في المتصفح يعكس مقدار المحتوى من الناحية النظرية. سنستخدم عنصر حارس بمقاس 1 بكسل × 1 بكسل مع تحويل لفرض ترتيب العنصر الذي يحتوي على العناصر - المدرج - على الارتفاع. وسنعزز كل عنصر في المدرج إلى طبقته الخاصة للتأكد من أن طبقة المدرج نفسها فارغة تمامًا. بدون لون للخلفية، لا شيء. وإذا كانت طبقة المدرج غير فارغة، فلن تكون مؤهلة للظهور في المتصفح وسيتعين علينا تخزين زخرفة على بطاقة الرسومات الخاصة بنا بارتفاع 200,000 بكسل. بالتأكيد غير صالحة على جهاز جوّال.

عند التمرير، سنتحقق مما إذا كان إطار العرض قريبًا بدرجة كافية نهاية المدرج. إذا كان الأمر كذلك، سنعمل على تمديد المدرج من خلال تحريك الحارس ونقل العناصر التي تركت إطار العرض إلى الجزء السفلي المدرج وملئها بمحتوى جديد.

مدرّج الإعلانات سانتنال إطار العرض

ينطبق الشيء نفسه على التمرير في الاتجاه الآخر. ومع ذلك، لن نتحرك أبدًا تقليص المدرج في عمليات التنفيذ لدينا، بحيث يظل موضع شريط التمرير متسقة.

ملفات Tombstones

كما ذكرنا سابقًا، نحاول جعل مصدر البيانات يتصرف كشيء ما في العالم الحقيقي. مع وقت استجابة الشبكة وكل شيء آخر. هذا يعني أنه إذا بالاستفادة من التمرير السريع، حيث يمكنهم التنقل بسهولة إلى ما بعد العنصر الأخير التي لدينا بيانات عنها. إذا حدث ذلك، سنضع عنصر شاهد قبر - عنصر نائب - سيتم استبداله بالعنصر بمحتوى فعلي بمجرد وصول البيانات. يُعاد تدوير شواهد القبور أيضًا ويضم مسبحًا منفصلاً عناصر DOM القابلة لإعادة الاستخدام. نحتاج إلى ذلك حتى نتمكن من إجراء انتقال جيد من تومب إلى العنصر المعبأ بالمحتوى، والذي كان من الممكن أن يكون مضايقة المستخدم وقد يؤدي في الواقع إلى فقدان تتبع ما كان التركيز عليها.

مثل
مقبرة أحجار كريمة جدًا. يا للروعة

التحدي المثير للاهتمام هنا هو أن العناصر الحقيقية يمكن أن يكون ارتفاعها أكبر من عنصر علامة التبويب هذه نظرًا لاختلاف كميات النصوص لكل عنصر أو مرفق . لحل هذه المشكلة، سنعدّل موضع التمرير الحالي في كل مرة. البيانات ويتم استبدال شاهد القبر أعلى إطار العرض لإرساء موضع التمرير إلى عنصر ما بدلاً من قيمة البكسل. هذا المفهوم هو تسمى ارتساء التمرير.

تمرير الارتساء

سيتم استدعاء نقطة الارتساء الخاصة بالتمرير عند استبدال شواهد القبور وكذلك عند تغيير حجم النافذة (وهو ما يحدث أيضًا عندما يتم يتم قلبه!). سيتعين علينا تحديد العنصر الأكثر ظهورًا في إطار العرض. ونظرًا لأن هذا العنصر يمكن أن يكون مرئيًا جزئيًا فقط، فسنعيد أيضًا تخزن الإزاحة من أعلى العنصر حيث يبدأ إطار العرض.

تمرير مخطط الارتساء

فإذا تم تغيير حجم إطار العرض وتغير المدرج، فيمكننا استعادة موقف يبدو مطابق بصريًا للمستخدم. حقق الفوز! باستثناء الحجم الذي تم تغيير حجمه نافذة تعني أنه من المحتمل أن يكون كل عنصر قد تغير ارتفاعه، فكيف معرفة المسافة التي يجب وضع المحتوى الثابت فيها؟ نحن لا نفعل ذلك! لمعرفة ذلك سيتعين علينا تخطيط كل عنصر أعلى العنصر الارتساء وجمع كل وارتفاعاتهم فقد يتسبب هذا في توقف كبير بعد تغيير الحجم، ولا نريد ذلك. بدلاً من ذلك، نلجأ إلى افتراض أن جميع العناصر أعلاه لها نفس المقاس على شكل ضريح ونعدّل موضع التمرير وفقًا لذلك. نظرًا لأن العناصر ويتم تمريرها إلى المدرج، ونعدّل موضع التمرير، وسنؤجل بشكل فعال يعمل التخطيط حتى وقت الحاجة إليه بالفعل.

التنسيق

لقد تخطّيت أحد التفاصيل المهمة: التنسيق. كل عملية إعادة تدوير لعنصر DOM عادةً ما تعمل على طول مدرج الطائرات بالكامل، ما يقودنا إلى مستوى أدنى بكثير من هو 60 لقطة في الثانية. لتجنب هذا، نتحمل عبء أنفسنا ونستخدم عناصر ذات موضع كامل مع التحويلات. وبهذه الطريقة يمكننا التظاهر بأن جميع العناصر الموجودة في المدرج لا تزال أن تشغل مساحة في حين لا توجد سوى مساحة فارغة في الواقع. نظرًا لأننا نقوم بتخطيط أنفسنا، يمكننا تخزين المواضع التي ينتهي فيها كل عنصر في ذاكرة التخزين المؤقت ويمكننا تحميل العنصر الصحيح على الفور من ذاكرة التخزين المؤقت عندما يقوم المستخدم بالتمرير للخلف.

من الناحية المثالية، لا تتم إعادة عرض العناصر إلا مرة واحدة فقط عندما يتم إرفاقها بنموذج العناصر في المستند (DOM) ولا تزعجهم من إضافة أو إزالة عناصر أخرى على مدرج الطائرات. أي ولكن باستخدام المتصفحات الحديثة فقط.

الميزات الجديدة

ومؤخرًا، أضاف Chrome ميزة احتواء CSS، وهي ميزة التي تسمح لنا للمطورين بإخبار المتصفح بأن العنصر يحد التخطيط والطلاء. نظرًا لأننا نقوم بالتخطيط بأنفسنا هنا، فهو مدير طلب الاحتواء. عندما نضيف عنصرًا إلى المدرج، نعلم لا يلزم أن تتأثر العناصر الأخرى بعملية الإرسال. لذلك يجب على كل عنصر أن تحصل على contain: layout. كما أننا لا نريد التأثير على بقية موقعنا على الويب، إذًا، يجب أن يحصل المدرج نفسه على توجيه النمط هذا أيضًا.

شيء آخر نظرنا فيه هو استخدام IntersectionObservers كآلية لرصد متى مرر المستخدم كثيرًا بما يكفي لبدء إعادة تدوير العناصر وتحميل عناصر البيانات. ومع ذلك، يتم تحديد IntersectionObservers ليكون وقت استجابة عاليًا (كما لو باستخدام requestIdleCallback)، لذلك قد نشعر في الواقع أقل استجابة باستخدام مراقبة التقاطعات أكثر من غيرها. حتى عملية التنفيذ الحالية باستخدام يواجه حدث scroll هذه المشكلة، حيث يتم إرسال أحداث التمرير على أساس "الجهد الأفضل". وفي النهاية، تعاونت شركة Houdini's Compositor Worklet ستكون الحل عالي الدقة لهذه المشكلة.

لا تزال غير مثالية

تطبيقنا الحالي لإعادة تدوير DOM ليس مثاليًا لأنه يضيف جميع العناصر التي تمر خلال إطار العرض، بدلاً من الاهتمام بإطارات العرض على الشاشة فعليًا. وهذا يعني أنه عندما تقوم بالتمرير بسرعة حقيقية، فإنك تضع كثيرًا من العمل للتخطيط والطلاء في Chrome لدرجة أنه لا يستطيع مواكبة ذلك. ستنتهي لا ترى أي شيء سوى الخلفية. إنها ليست نهاية العالم ولكن بالتأكيد شيء يجب تحسينه.

نأمل أن ترى كيف يمكن أن تصبح المشكلات البسيطة الصعبة عندما تريد تجمع بين تجربة المستخدم الرائعة ومعايير الأداء العالية. مع أصبحت تطبيقات الويب التقدّمية تجارب أساسية على الهواتف الجوّالة، أكثر أهمية وسيتعين على مطوّري الويب مواصلة الاستثمار في واستخدام أنماط تحترم قيود الأداء.

يمكنك العثور على جميع الرموز في مستودعنا. لقد فعلنا ونبذل قصارى جهدنا لجعلها قابلة لإعادة الاستخدام، ولكن لن ننشرها كمكتبة فعلية على npm أو كمستودع منفصل. يكون الاستخدام الأساسي لأغراض تعليمية.