قياس أداء جافا سكريبت

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

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

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





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

أسلوب Performance.now ()


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

لقياس أداء جزء التعليمات البرمجية باستخدام الطريقة performance.now()، تحتاج إلى إجراء قياسات زمنية ، وحفظ نتائج هذه القياسات في متغيرات ، ثم طرح نتائج الأول من نتائج القياس الثاني:

const t0 = performance.now();
for (let i = 0; i < array.length; i++) 
{
  // - 
}
const t1 = performance.now();
console.log(t1 - t0, 'milliseconds');

في Chrome ، بعد تنفيذ هذا الرمز ، يمكنك الحصول على شيء مثل هذا:

0.6350000001020817 "milliseconds"

في Firefox ، مثل هذا:

1 milliseconds

كما ترون ، فإن نتائج القياس التي تم الحصول عليها في متصفحات مختلفة مختلفة تمامًا. والحقيقة هي أنه في Firefox 60 ، يتم تقليل دقة النتائج التي يتم إرجاعها بواسطة Performance API. سنتحدث أكثر عن هذا.

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

في حالتنا ، نحن نتحدث عن قياس أداء الوظائف ، لذلك لدينا فرص كافية توفرها الطريقةperformance.now().

Date.now () و performance.now ()


هنا قد تعتقد أنه يمكنك استخدام الطريقة لقياس الأداء Date.now(). هذا ممكن بالفعل ، ولكن هذا النهج له عيوب. تُعيد

هذه الطريقة Date.now()الوقت بالمللي ثانية الذي انقضى منذ عصر يونكس (1970-01-01T00: 00: 00Z) وتعتمد على ساعة النظام. هذا لا يعني فقط أن هذه الطريقة ليست دقيقة مثل performance.now()، ولكنها ، على النقيض من ذلك performance.now()، تُرجع قيمًا يمكن ، في ظروف معينة ، أن تستند إلى مؤشرات ساعة غير صحيحة. إليك ما يقوله Rich Gentlekor ، وهو مبرمج مرتبط بمحرك WebKit: "ربما لا يعتقد المبرمجون أن القراءات عادت عندماDateاستنادًا إلى وقت النظام ، من المستحيل تمامًا استدعاء مثالية لمراقبة التطبيقات الحقيقية. تحتوي معظم الأنظمة على برنامج خفي يقوم بمزامنة الوقت بانتظام. يعد ضبط ساعة النظام لبضع ثوانٍ كل 15-20 دقيقة أمرًا شائعًا. مع هذا التردد ، ستكون إعدادات الساعة حوالي 1٪ من قياسات فترات 10 ثانية غير دقيقة. "

طريقة Console.time ()


قياس الوقت باستخدام واجهة برمجة التطبيقات هذه بسيط للغاية. يكفي ، قبل الكود الذي تحتاج إلى تقييم أدائه ، اتصل بالطريقة console.time()، وبعد هذا الكود - الطريقة console.timeEnd(). في هذه الحالة ، تحتاج إحدى الطرق الأخرى لتمرير نفس وسيطة السلسلة. في صفحة واحدة ، يمكن استخدام ما يصل إلى 10000 من هذه المؤقتات في وقت واحد.

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

console.time('test');
for (let i = 0; i < array.length; i++) {
  // - 
}
console.timeEnd('test');

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

في Chrome ، سيبدو شيئًا مثل هذا:

test: 0.766845703125ms

في Firefox ، مثل هذا:

test: 2ms - timer ended

في الواقع ، كل شيء هنا مشابه جدًا لما رأيناه أثناء العمل performance.now().

قوة الطريقة console.time()هي سهولة استخدامها. أي أننا نتحدث عن حقيقة أن تطبيقه لا يتطلب الإعلان عن المتغيرات المساعدة وإيجاد الفرق بين المؤشرات المسجلة فيها.

تقليل وقت الدقة


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

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

في Firefox 60 ، كما سبق ذكره ، يتم تقليل دقة نتائج قياس الوقت . يتم ذلك عن طريق تعيين privacy.reduceTimerPrecisionقيمة الخاصية إلى 2 مللي ثانية.

شيء يجب مراعاته عند اختبار الأداء


الآن لديك أدوات تحت تصرفك لقياس أداء وظائف JavaScript. ولكن قبل الشروع في العمل ، تحتاج إلى النظر في بعض الميزات التي سنتحدث عنها الآن.

▍ فرق تسد


لنفترض أنك ، أثناء تصفية بعض البيانات ، انتبهت إلى بطء تشغيل التطبيق. لكنك لا تعرف بالضبط أين اختناق الأداء.

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

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

كلما قل الرمز بين الاستدعاءات للطرق التي تقيس الوقت ، قل احتمال قياس شيء غير ذي صلة بحالة المشكلة.

▍ ضع في الاعتبار ميزات سلوك الوظائف عند قيم الإدخال المختلفة


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

يجب استدعاء الوظائف عند البحث عن الأداء مع بيانات الإدخال التي تشبه تلك الحقيقية قدر الإمكان.

functions تشغيل الوظائف عدة مرات


افترض أن لديك وظيفة تتكرر عبر مصفوفة. تقوم بإجراء بعض العمليات الحسابية باستخدام كل عنصر من عناصر المصفوفة ، وبعد ذلك تقوم بإرجاع مصفوفة جديدة مع نتائج الحسابات. بالتفكير في تحسين هذه الوظيفة ، فأنت تريد معرفة ما يعمل بشكل أسرع في موقفك - حلقة forEachأو حلقة عادية for.

فيما يلي خياران لهذه الميزة:

function testForEach(x) {
  console.time('test-forEach');
  const res = [];
  x.forEach((value, index) => {
    res.push(value / 1.2 * 0.1);
  });

  console.timeEnd('test-forEach')
  return res;
}

function testFor(x) {
  console.time('test-for');
  const res = [];
  for (let i = 0; i < x.length; i ++) {
    res.push(x[i] / 1.2 * 0.1);
  }

  console.timeEnd('test-for')
  return res;
}

اختبر الوظائف:

const x = new Array(100000).fill(Math.random());
testForEach(x);
testFor(x);

بعد تشغيل الكود ، نحصل على النتائج التالية:

test-forEach: 27ms - timer ended
test-for: 3ms - timer ended

بدت الدورة forEachأبطأ بكثير من الدورة for. بعد كل شيء ، تشير نتائج الاختبار إلى هذا بالضبط؟

في الواقع ، بعد اختبار واحد ، من السابق لأوانه استخلاص مثل هذه الاستنتاجات. لنحاول استدعاء الوظائف مرتين:

testForEach(x);
testForEach(x);
testFor(x);
testFor(x);

نحصل على ما يلي:

test-forEach: 13ms - timer ended
test-forEach: 2ms - timer ended
test-for: 1ms - timer ended
test-for: 3ms - timer ended

اتضح أن الوظيفة التي تُستخدم فيها forEach، تسمى المرة الثانية ، سريعة مثل تلك التي يتم استخدامها فيها for. ولكن ، نظرًا لحقيقة أن forEachالوظيفة الأولى تستدعي ، تعمل الوظيفة بشكل أبطأ بكثير ، فقد لا تزال لا تستحق استخدامها.

▍ اختبار الأداء في المتصفحات المختلفة


تم إجراء الاختبارات أعلاه في Firefox. ولكن ماذا لو قمت بتنفيذها في Chrome؟ ستكون النتائج مختلفة تمامًا:

test-forEach: 6.156005859375ms
test-forEach: 8.01416015625ms
test-for: 4.371337890625ms
test-for: 4.31298828125ms

والحقيقة هي أن متصفحي Chrome و Firefox يعتمدان على محركات JavaScript مختلفة تنفذ تحسينات أداء مختلفة. من المفيد جدًا معرفة هذه الاختلافات.

في هذه الحالة ، يتمتع Firefox بتحسين أفضل forEachمع إدخال مماثل. والدورة forأسرع من forEachكل من Chrome و Firefox. نتيجة لذلك ، من الأفضل الخوض في متغير الوظيفة ج for.

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

▍ تطبيق حدود مصطنعة على موارد النظام


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

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

باستخدام هذا النهج ، يمكن أن تتحول 10 أو 50 مللي ثانية بسهولة إلى 500.

▍ قياس الأداء النسبي


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

ملخص


في هذه المقالة ، استعرضنا بعض واجهات برمجة تطبيقات JavaScript المصممة لقياس الأداء. تحدثنا عن كيفية استخدامها لتحليل الكود الحقيقي. أعتقد أنه من أجل إجراء بعض القياسات البسيطة ، من الأسهل استخدامها console.time().

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

القراء الأعزاء! إذا كنت تراقب باستمرار أداء مشاريعك ، فيرجى إخبارنا بكيفية القيام بذلك.


All Articles