أفضل ممارسات التحميل الكسول

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

إبقاء الجزء المرئي من الصفحة

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

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

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

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

let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
  // lazy-loading image code goes here
}, {
  rootMargin: "0px 0px 256px 0px"
});

إذا كانت قيمة rootMargin تبدو مشابهة للقيم التي حدّدتها لسمة margin في CSS، لأنّها كذلك. في هذه الحالة، يتم توسيع الهامش السفلي للعنصر المرصود (إطار عرض المتصفّح تلقائيًا، ولكن يمكن تغييره إلى عنصر معيّن باستخدام السمة root) بمقدار 256 بكسل. وهذا يعني أنّه سيتم تنفيذ وظيفة معاودة الاتصال عندما يكون عنصر الصورة ضمن إطار العرض بمقدار 256 بكسل ويبدأ تحميل الصورة قبل أن يراها المستخدم.

ولتحقيق هذا التأثير نفسه في المتصفّحات التي لا تتيح ميزة "مراقبة التقاطع"، استخدِم رمز معالجة حدث التمرير واضبط علامة getBoundingClientRect لتضمين مورد احتياطي.

تغيير التصميم والعناصر النائبة

يمكن أن تؤدي وسائط التحميل الكسول إلى تغيير التنسيق في حال عدم استخدام العناصر النائبة. قد تكون هذه التغييرات مربكة للمستخدمين وتؤدي إلى تشغيل عمليات تنسيق DOM باهظة الثمن التي تستهلك موارد النظام وتساهم في البيانات غير المحتملة. ننصحك على الأقل باستخدام عنصر نائب بلون خالص يشغل الأبعاد نفسها للصورة المستهدفة، أو أساليب مثل LQIP أو SQIP التي تشير إلى محتوى عنصر الوسائط قبل تحميله.

بالنسبة إلى علامات <img>، يجب أن يشير src في البداية إلى عنصر نائب إلى أن يتم تعديل هذه السمة باستخدام عنوان URL النهائي للصورة. استخدِم السمة poster في عنصر <video> للإشارة إلى صورة عنصر نائب. بالإضافة إلى ذلك، استخدِم السمتَين width وheight في كلتا العلامتين <img> و<video>. يضمن ذلك أن الانتقال من العناصر النائبة إلى الصور النهائية لن يغير حجم العنصر المعروض أثناء تحميل الوسائط.

تأخّر فك ترميز الصور

قد يؤدي تحميل صور كبيرة في JavaScript وإفلاتها في DOM إلى ربط سلسلة التعليمات الرئيسية، ما قد يؤدي إلى عدم استجابة واجهة المستخدم لفترة زمنية قصيرة أثناء تنفيذ عملية فك الترميز. يمكن أن يؤدي فك ترميز الصور بشكل غير متزامن باستخدام الطريقة decode قبل إدراجها في نموذج العناصر في المستند (DOM) إلى تقليل هذا النوع من البيانات غير المهمة، ولكن يُرجى العلم بأنّ هذه الطريقة لا تتوفّر في كل مكان حتى الآن، كما أنّها تزيد من التعقيد في منطق التحميل الكسول. إذا أردت استخدامه، عليك التحقّق من استخدامه. في ما يلي طريقة استخدام Image.decode() مع عنصر احتياطي:

var newImage = new Image();
newImage.src = "my-awesome-image.jpg";

if ("decode" in newImage) {
  // Fancy decoding logic
  newImage.decode().then(function() {
    imageContainer.appendChild(newImage);
  });
} else {
  // Regular image load
  imageContainer.appendChild(newImage);
}

يمكنك الاطّلاع على رابط CodePen هذا للاطّلاع على تعليمات برمجية مشابهة لهذا المثال بشكل عملي. إذا كانت معظم صورك صغيرة إلى حد ما، قد لا يفيدك ذلك كثيرًا، ولكنه يمكن أن يساعد بالتأكيد في تقليل البيانات غير المحتملة عند التحميل الكسول للصور الكبيرة وإدراجها في نموذج العناصر في المستند (DOM).

عند عدم تحميل المحتوى

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

وعلى الرغم من أنّ هذه الحالات نادرة نسبيًا، قد يتطلّب الأمر منك استخدام خطة احتياطية في حال تعذُّر التحميل الكسول. بالنسبة للصور، قد يبدو هذا الحل على النحو التالي:

var newImage = new Image();
newImage.src = "my-awesome-image.jpg";

newImage.onerror = function(){
  // Decide what to do on error
};
newImage.onload = function(){
  // Load the image
};

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

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

مدى توفُّر JavaScript

ولا يمكن افتراض أنّ لغة JavaScript متاحة دائمًا. إذا كنت تريد تحميل الصور باستخدام التحميل الكسول، يمكنك توفير ترميز <noscript> الذي سيعرض الصور في حال عدم توفّر JavaScript. يتضمّن أبسط مثال احتياطي ممكن استخدام عناصر <noscript> لعرض الصور في حال إيقاف JavaScript:

أنا صورة!

في حال إيقاف JavaScript، ستظهر للمستخدمين كل من صورة العنصر النائب والصورة المضمّنة مع عناصر <noscript>. لحلّ هذه المشكلة، ضَع فئة no-js على العلامة <html> على النحو التالي:

<html class="no-js">

ضع بعد ذلك سطرًا واحدًا من النص البرمجي المضمّن في <head> قبل طلب أي أوراق أنماط من خلال علامات <link> التي تزيل الفئة no-js من العنصر <html> إذا كانت لغة JavaScript مفعّلة:

<script>document.documentElement.classList.remove("no-js");</script>

أخيرًا، يمكنك استخدام بعض CSS لإخفاء العناصر بفئة من الكسول عند عدم توفر JavaScript:

.no-js .lazy {
  display: none;
}

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