شناسایی جاوا اسکریپت با اجرای سنگین

جاوا اسکریپت سنگین می‌تواند تأثیر مخربی بر عملکرد بار کردن صفحه و تعامل‌پذیری داشته باشد. برنامه‌های وب مدرن بیش‌از هر زمان دیگری به جاوا اسکریپت از منابع متعدد متکی هستند. این موارد شامل خود کد برنامه (و کد چارچوبی که به آن متکی است)، و همچنین اسکریپت‌های طرف سومی است که عملکردهایی مانند ابزاره‌های گپ و پخش‌کننده‌های ویدیو را اضافه می‌کنند. تحلیل‌های پشت صحنه و اسکریپت‌های بازاریابی نیز از عوامل رایج هستند که به‌راحتی فراموش می‌شوند.

شناسایی علل ریشه‌ای پاسخگو نبودن صفحه وب می‌تواند دشوار باشد و برای اجرای ردیابی یا نمایه‌سازی عملکرد وب و نحوه تفسیر نتایج به تخصص خاصی نیاز است. به‌علاوه، داده‌های فیلد اغلب با داده‌های آزمایشگاهی بسیار متفاوت است، زیرا داده‌های آزمایشگاهی فقط زیرمجموعه کوچکی از سناریوهای کاربر واقعی را تکرار می‌کند. این امر می‌تواند شناسایی علل ریشه‌ای عملکرد ضعیف را، به‌ویژه برای تعامل‌ها، دشوار کند.

Long Animation Frames API یک میانای برنامه‌سازی کاربردی سبک است که می‌توان از آن برای شناسایی جاوا اسکریپت سنگین درحال اجرا در فیلد استفاده کرد. متن سنگین می‌تواند یک متن طولانی باشد یا متنی که چند بار درطول چرخه حیات صفحه اجرا می‌شود.

نحوه پیاده‌سازی

فریم‌های پویانمایی طولانی بااستفاده از میانای PerformanceObserver پایش می‌شوند. وقتی پرداز قاب پویانمایی بیشتر از ۵۰ میلی‌ثانیه طول بکشد، ورودی long-animation-frame را منتشر می‌کند. این ورودی حاوی اطلاعاتی درباره قاب پویانمایی طولانی است، ازجمله مدت‌زمان قاب و کدهای دستوری که درطول قاب اجرا شده‌اند.

ورودی 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 پشتیبانی نمی‌کنند آن را نادیده می‌گیرند، بنابراین می‌توان بدون بازگشت از آن به‌طور ایمن استفاده کرد. در بیشتر موارد، فرصت‌های عملکردی که شناسایی می‌کند برای مرورگرهای دیگر نیز اعمال خواهد شد.