【阿里场景题】面试官:如何统计长任务时间、长任务执行次数?

哈喽,大家好,今天为大家分享一篇前端场景题,由我们得导师uncle13提供。

在 JavaScript 中,可以使用 Performance API 中的 PerformanceObserver 来监视和统计长任务(Long Task)。长任务是指那些执行时间超过 50 毫秒的任务,这些任务可能会阻塞主线程,影响页面的交互性和流畅性。

1. 使用console.time()console.timeEnd()

JavaScript 提供了 console.time()console.timeEnd() 方法来测量代码块的执行时间。

console.time('longTask');
// 你的长任务代码
for (let i = 0; i < 1e7; i++) {
  // ...
}
console.timeEnd('longTask');

简单粗暴。这种方法仅适用于手动测量,并且每次都需要手动添加代码。

2.使用 Performance API:

浏览器的 Performance API 提供了高精度的时间戳,可以用来测量长任务的时间和执行次数。performanceentry事件,可以监测到长任务并获取相关信息。

// 创建一个性能观察者实例来订阅长任务
let observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
 console.log("Long Task detected:");
 console.log(`Task Start Time: ${entry.startTime}, Duration: ${entry.duration}`);
}
});

// 开始观察长任务
observer.observe({ entryTypes: ["longtask"] });

// 启动长任务统计数据的变量
let longTaskCount = 0;
let totalLongTaskTime = 0;

// 更新之前的性能观察者实例,以增加统计逻辑
observer = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
 longTaskCount++; // 统计长任务次数
 totalLongTaskTime += entry.duration; // 累加长任务总耗时
 // 可以在这里添加其他逻辑,比如记录长任务发生的具体时间等
});
});

// 再次开始观察长任务
observer.observe({ entryTypes: ["longtask"] });

在上面的代码中,创建了一个PerformanceObserver对象来订阅长任务。每当检测到长任务时,它会向回调函数传递一个包含长任务性能条目的列表。在这个回调中,可以统计长任务的次数和总耗时。

以下是如何在实际使用中停止观察和获取当前的统计数据:


// 停止观察能力
observer.disconnect();

// 统计数据输出
console.log(`Total number of long tasks: ${longTaskCount}`);
console.log(`Total duration of all long tasks: ${totalLongTaskTime}ms`);

3. 使用AOP(面向切面编程)

通过AOP,可以在函数执行前后添加额外的逻辑,而无需修改原函数。这可以通过使用像 Function.prototype.beforeFunction.prototype.after 这样的自定义方法(虽然这些方法在原生JavaScript中不存在,但可以通过原型扩展实现)或使用专门的库(如 lodash 的 _.wrap())来实现。

4. 使用 Web Workers

使用 Web Workers 统计长任务时间和执行次数的基本思路是将性能监测的逻辑放入 Worker 中,从而使得监测本身不会成为主线程的负担。Worker 可以周期性地向主线程报告长任务的信息,而主线程则可以更新用户界面或记录这些数据。


// worker.js
self.addEventListener('message'function(e{
  if (e.data === 'start') {
    // 开始监测长任务
    self.performance.observe({ entryTypes: ['longtask'] });
  }
});

self.performance.addEventListener('longtask'function(entry{
  // 当检测到长任务时,发送消息到主线程
  self.postMessage({
    duration: entry.duration,
    startTime: entry.startTime
  });
});

// 主线程
const worker = new Worker('worker.js');

// 启动 Worker 监测长任务
worker.postMessage('start');

let longTasksCount = 0;
let totalDuration = 0;

worker.onmessage = function(e{
  // 更新长任务统计信息
  longTasksCount++;
  totalDuration += e.data.duration;

  // 可以在这里更新用户界面或记录数据
  console.log(`长任务持续时间: ${e.data.duration}ms, 开始时间:${e.data.startTime}`);
  console.log(`长任务总数: ${longTasksCount}, 总持续时间:${totalDuration}ms`);
};

// 如果需要,可以停止监测
// worker.postMessage('stop');

在这个例子中,Worker 使用了 performance.observe 方法来监测长任务。每当检测到一个长任务时,它就会向主线程发送一条消息,其中包含长任务的持续时间和开始时间。主线程接收到这些消息后,可以更新长任务的统计信息,并执行相应的操作,比如记录数据或更新用户界面

5. 使用性能监控工具

可以考虑使用像 Lighthouse、Chrome DevTools 的 Performance Tab 或其他前端性能监控工具来自动识别和测量长任务。这些工具通常提供了更详细的性能数据和分析。

6. 自定义解决方案

如果需要将这些统计数据发送到服务器进行分析或存储,可以使用 AJAX、Fetch API 或其他方法将这些数据发送到后端 API。另外,通过定期检查时间戳差值来检测长任务。例如,可以在requestAnimationFrame回调中记录时间戳,并检查与上次回调的时间差是否超过50毫秒。

注意事项

  • 长任务:在前端中,长任务通常指的是那些阻塞主线程超过50毫秒的任务,因为它们可能导致用户体验下降(如页面卡顿)。
  • 不要过度优化:虽然监控和优化性能很重要,但也要避免过度优化,因为这可能会使代码变得复杂且难以维护。始终在性能和可读性之间找到平衡。

最后

还没有使用过我们刷题网站(https://fe.ecool.fun/)或者前端面试题宝典的同学,如果近期准备或者正在找工作,千万不要错过,题库主打无广告和更新快哦~。

老规矩,也给我们团队的辅导服务打个广告。