تحسين تنفيذ JavaScript

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

بول لويس
بول لويس

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

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

ومع ذلك، هناك بعض الأشياء التي يمكنك بالتأكيد القيام بها لمساعدة تطبيقاتك على تنفيذ JavaScript بشكل جيد.

ملخّص

  • تجنب ضبط المهلة أو setInterval للتحديثات المرئية؛ دائمًا استخدم requestAnimationFrame بدلاً منها.
  • نقل JavaScript لفترة طويلة من سلسلة التعليمات الرئيسية إلى "عاملو الويب"
  • استخدام المهام الصغيرة لإجراء تغييرات DOM على عدة إطارات.
  • استخدِم المخطط الزمني وأداة تحليل JavaScript في أدوات مطوري البرامج في Chrome لتقييم تأثير JavaScript.

استخدام requestAnimationFrame لإجراء التغييرات المرئية

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

/**
    * If run as a requestAnimationFrame callback, this
    * will be run at the start of the frame.
    */
function updateScreen(time) {
    // Make visual updates here.
}

requestAnimationFrame(updateScreen);

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

تعيين المهلة التي تتسبب في تفويت المتصفح لإطار ما.

في الواقع، اعتادت jQuery على استخدام السمة setTimeout لسلوك animate. وتم تغييره ليستخدم requestAnimationFrame في الإصدار 3. إذا كنت تستخدم إصدارًا قديمًا من jQuery، يمكنك تصحيحه لاستخدام requestAnimationFrame، ننصح بشدة باستخدامه.

تقليل التعقيد أو استخدام Web Worker

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

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

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

var dataSortWorker = new Worker("sort-worker.js");
dataSortWorker.postMesssage(dataToSort);

// The main thread is now free to continue working on other things...

dataSortWorker.addEventListener('message', function(evt) {
    var sortedData = evt.data;
    // Update data on screen...
});

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

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

معرفة "ضريبة الإطار" في JavaScript

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

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

تسجيل أداء في "أدوات مطوري البرامج في Chrome"

يوفر القسم الرئيسي رسمًا بيانيًا شاملاً لاستدعاءات JavaScript حتى تتمكن من تحليل الدوال التي تم طلبها بالضبط والمدة التي استغرقتها كل منها.

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

راجِع البدء في تحليل أداء وقت التشغيل لمعرفة كيفية استخدام لوحة "الأداء".

تجنُّب التحسين الدقيق لJavaScript

قد يكون من اللطيف أن تعرف أنّ المتصفح يمكنه تنفيذ نسخة واحدة من شيء أسرع 100 مرة من إجراء آخر، مثل أن يكون طلب offsetTop لعنصر أسرع من الحوسبة getBoundingClientRect()، ولكن من المؤكّد دائمًا أنّه سيتم طلب دوال مثل هذه عدد قليل من المرات فقط لكل إطار، لذلك عادةً ما يكون هدر الجهد للتركيز على هذا الجانب من أداء JavaScript. وعادةً ما تحفظ أجزاءً من المللي ثانية فقط.

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

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