النصّ المختصر: يمكنك إعادة استخدام عناصر DOM وإزالة العناصر البعيدة عن مجال العرض. استخدِم العناصر النائبة لمراعاة البيانات المتأخرة. في ما يلي عرض توضيحي والرمز لشريط التمرير العميق.
تظهر ميزة "التمرير اللا نهائي" في جميع أنحاء الإنترنت. هناك قائمة بالفنانين في Google Music، وأخرى في المخطط الزمني على Facebook، وأخرى في الخلاصة المباشرة على Twitter. تنقّل للأسفل، وقبل أن تصل إلى نهاية الصفحة، يظهر محتوى جديد بشكل سحري ويبدو أنّه ينبثق من العدم. وتوفّر هذه الطريقة تجربة سلسة للمستخدمين، ومن السهل التعرّف على مزاياها.
ومع ذلك، فإنّ التحدي الفني الذي يواجهه شريط التمرير اللانهائي أصعب مما يبدو. إنّ نطاق المشاكل التي تواجهها عند تنفيذ الإجراء المناسب هو واسع. تبدأ هذه المشاكل بأمور بسيطة، مثل أن تصبح الروابط في التذييل غير قابلة للوصول إليها عمليًا لأنّ المحتوى يستمر في دفع التذييل للأسفل. ولكن الصعوبة في حلّ المشكلات تزداد. كيف تتعامل مع حدث تغيير الحجم عندما يدير أحد المستخدمين هاتفه من الوضع العمودي إلى الوضع الأفقي أو كيف تمنع هاتفك من التوقّف عن العمل بشكل مؤلم عندما تصبح القائمة طويلة جدًا؟
The right thing™
اعتقدنا أنّ هذا السبب كافٍ لإنشاء عملية تنفيذ مرجعية توضّح طريقة معالجة كل هذه المشاكل بطريقة قابلة لإعادة الاستخدام مع الحفاظ على معايير الأداء.
سنستخدم 3 أساليب لتحقيق هدفنا: إعادة تدوير DOM، والعناصر التي تشير إلى أنّ المحتوى قد انتهى ، وربط الانتقال إلى أعلى الصفحة.
ستكون الحالة التجريبية عبارة عن نافذة محادثة مشابهة لتلك في Hangouts، حيث يمكننا التمرير في الرسائل. أول ما نحتاج إليه هو مصدر غير محدود من رسائل المحادثة. من الناحية الفنية، لا يمكن أن تكون أي من ميزات التمرير اللامتناهي حقًا لا متناهية، ولكن مع كمية البيانات المتاحة التي يمكن ضخها في هذه ميزات، قد تبدو كذلك. من أجل التبسيط، سنكتفي بتضمين مجموعة من رسائل المحادثة في الرمز البرمجي وسنختار الرسالة والكاتب والمرفقات الصورية في بعض الأحيان بشكل عشوائي مع إضافة بعض التأخير الاصطناعي لكي تبدو المحادثة أكثر شبهاً بالمحادثة في الشبكة الفعلية.

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

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

في حال تغيير حجم إطار العرض وتغيّر المدرج، يمكننا استعادة حالة تبدو متطابقة للمستخدم من الناحية المرئية. فوز! باستثناء أنّ تغيير حجم النافذة يؤدي إلى احتمالية تغيير ارتفاع كل عنصر، فكيف يمكننا معرفة مقدار خفض المحتوى المرتبط؟ لا نفعل ذلك. لمعرفة ذلك، علينا ترتيب كل عنصر فوق العنصر المرتبط به وجمع كل ارتفاعاته، ما قد يؤدي إلى توقف مؤقت كبير بعد تغيير الحجم، وهو ما لا نريده. بدلاً من ذلك، نفترض أنّ كل عنصر أعلاه هو بالحجم نفسه كقائمة المراجعات السابقة، ونعدّل موضع الانتقال للأعلى أو للأسفل وفقًا لذلك. وعندما يتم التمرير للأعلى أو للأسفل في العناصر لعرضها في الممر، نعدّل موضع التمرير، ما يؤخّر بشكل فعّال عمل التنسيق إلى حين الحاجة إليه.
التنسيق
لقد تخطّيتُ أحد التفاصيل المهمة: التنسيق. إنّ كل عملية إعادة استخدام لعنصر نموذج DOM ستؤدي عادةً إلى إعادة تصميم المدرج بالكامل، ما سيؤدي إلى انخفاض معدل عرض اللقطات عن المعدل المستهدف وهو 60 لقطة في الثانية. لتجنُّب ذلك، نتحمّل عبء التنسيق ونستخدم العناصر ذات الموضع المطلق مع عمليات التحويل. بهذه الطريقة، يمكننا أن نتظاهر بأنّ جميع العناصر في أعلى المدرج لا تزال تشغل مساحة، بينما في الواقع لا تتوفّر سوى مساحة فارغة. بما أنّنا نُجري ourselves عملية الترميز، يمكننا تخزين مواضع كل عنصر في ذاكرة التخزين المؤقت ويمكننا تحميل العنصر الصحيح من ذاكرة التخزين المؤقت على الفور عندما ينتقل المستخدم للخلف.
من المفترض أن تتم إعادة رسم العناصر مرة واحدة فقط عند إرفاقها بـ DOM وألا تتأثر بعمليات إضافة أو إزالة عناصر أخرى في الممر. هذا الإجراء ممكن، ولكن باستخدام المتصفّحات الحديثة فقط.
تعديلات حديثة
أضاف Chrome مؤخرًا ميزة "الحدّ CSS"، وهي ميزة
تسمح لنا كمطوّرين بإعلام المتصفّح بأنّ العنصر هو حدّ لحدود
التنسيق والتلوين. وبما أنّنا نُجري التنسيق بأنفسنا هنا، فهو أحد أهم
تطبيقات الاحتواء. عندما نضيف عنصرًا إلى المدرج، نعرف
أنّه ليس من الضروري أن تتأثر العناصر الأخرى بإعادة التنسيق. لذلك، يجب أن يحصل كل عنصر على contain: layout
. لا نريد أيضًا التأثير في بقية موقعنا الإلكتروني،
لذا يجب أن تحصل صفحة المدرج نفسها على تعليمات الأنماط هذه أيضًا.
من الأمور الأخرى التي أخذناها في الاعتبار استخدام
IntersectionObservers
كآلية لرصد الحالات التي ينتقل فيها
المستخدم إلى أسفل الصفحة بما يكفي لبدء إعادة تدوير العناصر وتحميل
بيانات جديدة. ومع ذلك، تم تحديد IntersectionObservers ليكون لها وقت استجابة مرتفع (كما لو كانت
مستخدِمة requestIdleCallback
)، لذلك قد نشعر بأنّه يتم الاستجابة بشكلٍ أقل باستخدام
IntersectionObservers مقارنةً بعدم استخدامها. يواجه الإجراء الحالي الذي ننفّذه باستخدام حدث
scroll
هذه المشكلة أيضًا، لأنّ أحداث الانتقال إلى أعلى أو أسفل الصفحة يتم إرسالها على أساس "أقصى جهد". في النهاية، سيكون Houdini’s Compositor Worklet
هو الحلّ العالي الدقة لهذه المشكلة.
لا يزال هناك بعض المشاكل
إنّ عملية إعادة تدوير DOM الحالية ليست مثالية لأنّها تضيف جميع العناصر التي تمر عبر مساحة العرض، بدلاً من الاهتمام فقط بالعناصر التي تظهر على الشاشة. وهذا يعني أنّه عند الانتقال للأعلى أو للأسفل بسرعة كبيرة، تُحمّل Chrome مهامًا كثيرة في ما يتعلّق بالتنسيق والعرض، ما يتسبب في تأخّر استجابة المتصفّح. لن يظهر لك سوى الخلفية. لا داعي للقلق، ولكن هناك نقاط يجب تحسينها.
نأمل أن تدرك مدى صعوبة حلّ المشاكل البسيطة عندما تريد دمج تجربة مستخدم رائعة مع معايير أداء عالية. مع تحول التطبيقات التقدّمية على الويب إلى تجارب أساسية على الهواتف الجوّالة، سيصبح ذلك أكثر أهمية وسيضطر مطوّرو الويب إلى مواصلة الاستثمار في استخدام أنماط تراعي قيود الأداء.
يمكن العثور على كل الرموز البرمجية في مستودعنا. لقد بذلنا قصارى جهدنا للحفاظ على إمكانية إعادة استخدامها، ولكن لن ننشرها كمكتبة فعلية على npm أو كمستودع منفصل. الاستخدام الأساسي هو تعليمي.