تحديد JavaScript التي تستهلك الكثير من الموارد

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

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

‫Long Animation Frames API هي واجهة برمجة تطبيقات خفيفة يمكن استخدامها لتحديد نصوص JavaScript البرمجية التي تستهلك الكثير من الموارد في المجال. يمكن أن يكون النص البرمجي الثقيل إما نصًا برمجيًا واحدًا يستغرق وقتًا طويلاً أو نصًا برمجيًا يتم تشغيله عدة مرات خلال مراحل نشاط الصفحة.

كيفية الإعداد

تتم مراقبة الصور المتحركة التي يستغرق عرضها وقتًا طويلاً باستخدام واجهة PerformanceObserver. ويُصدر إدخال long-animation-frame عندما يستغرق عرض إطار الصورة المتحركة أكثر من 50 ملي ثانية. يحتوي الإدخال على معلومات حول صور متحركة يستغرق عرضها وقتًا طويلاً، بما في ذلك مدة الإطار والنصوص البرمجية التي تم تنفيذها خلاله.

يحتوي الإدخال long-animation-frame على السمة scripts، وهي مصفوفة من عناصر PerformanceScript. يحتوي كل عنصر PerformanceScript على معلومات حول النص البرمجي الذي تم تنفيذه أثناء عرض الصور المتحركة التي يستغرق عرضها وقتًا طويلاً، بما في ذلك sourceURL وduration للنص البرمجي.

مثال على تحديد النصوص البرمجية التي تستغرق أطول وقت في التشغيل وتساهم في عرض صور متحركة يستغرق عرضها وقتًا طويلاً

// Accumulate all script entries across the page lifecycle so no
// data is lost between observer callbacks.
const allScripts = [];

const observer = new PerformanceObserver(list => {
  // Collect all script entries across frames to find the biggest offenders.
  allScripts.push(...list.getEntries().flatMap(entry => entry.scripts));

  // Group by sourceURL so you can identify which scripts contribute
  // the most total time, even if each individual invocation is short.
  const scriptSource = [...new Set(allScripts.map(script => script.sourceURL))];
  const scriptsBySource = scriptSource.map(sourceURL => ([sourceURL,
      allScripts.filter(script => script.sourceURL === sourceURL)
  ]));
  const processedScripts = scriptsBySource.map(([sourceURL, scripts]) => ({
    sourceURL,
    count: scripts.length,
    totalDuration: scripts.reduce((subtotal, script) => subtotal + script.duration, 0)
  }));

  // Only include scripts above a certain threshold to reduce noise.
  const heavyScripts = processedScripts.filter(script => {
    return script.totalDuration > 100;
  });

  // Sort by total duration so the worst offenders appear first,
  // making it easier to prioritize optimization efforts.
  heavyScripts.sort((a, b) => b.totalDuration - a.totalDuration);

  // Log to the console for local debugging. In production, replace
  // this with a call to send the data to your analytics service.
  console.table(heavyScripts);
});

// Use buffered: true to capture any long frames that occurred before
// this observer was registered.
observer.observe({type: 'long-animation-frame', buffered: true});

أفضل الممارسات

  • يُفضَّل استخدام Long Animation Frames API بدلاً من البدائل، مثل JS Self-Profiling API، التي تزيد من أعباء وقت التشغيل.
  • يجب تلخيص المعلومات الأساسية لأنّ واجهة Long Animation Frames API تحتوي على الكثير من التفاصيل.
  • يجب إرسال المعلومات المطلوبة إلى خدمة إحصاءات في مرحلة الإنتاج.

توافق المتصفّح واستراتيجيات الاحتياط

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