性能优化面试题

1. 前端性能指标

性能指标概述

  • 概念解释:

    • FCP (First Contentful Paint): 首次内容绘制

    • LCP (Largest Contentful Paint): 最大内容绘制

    • TTI (Time to Interactive): 可交互时间

    • TBT (Total Blocking Time): 总阻塞时间

    • CLS (Cumulative Layout Shift): 累积布局偏移

// 1. Performance API 使用
// 性能指标监控
const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    if (entry.entryType === "largest-contentful-paint") {
      console.log("LCP:", entry.startTime);
    }
    if (entry.entryType === "first-contentful-paint") {
      console.log("FCP:", entry.startTime);
    }
  }
});

observer.observe({
  entryTypes: ["largest-contentful-paint", "first-contentful-paint"],
});

// 2. Web Vitals 库使用
import { getLCP, getFID, getCLS } from "web-vitals";

function sendToAnalytics({ name, delta, id }) {
  // 发送性能数据到分析服务
  fetch("/analytics", {
    method: "POST",
    body: JSON.stringify({ name, delta, id }),
  });
}

getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getLCP(sendToAnalytics);

性能监控方案

// 1. 自定义性能监控
class PerformanceMonitor {
  constructor() {
    this.metrics = {};
    this.init();
  }

  init() {
    // 记录页面加载时间
    window.addEventListener("load", () => {
      const timing = performance.timing;
      this.metrics.loadTime = timing.loadEventEnd - timing.navigationStart;
      this.metrics.domReady =
        timing.domContentLoadedEventEnd - timing.navigationStart;
      this.sendMetrics();
    });

    // 记录资源加载时间
    const observer = new PerformanceObserver((list) => {
      const entries = list.getEntries();
      entries.forEach((entry) => {
        if (entry.entryType === "resource") {
          this.metrics[entry.name] = entry.duration;
        }
      });
    });

    observer.observe({ entryTypes: ["resource"] });
  }

  sendMetrics() {
    // 发送性能数据
    navigator.sendBeacon("/analytics", JSON.stringify(this.metrics));
  }
}

// 2. 错误监控
window.addEventListener("error", (event) => {
  const error = {
    message: event.message,
    filename: event.filename,
    lineno: event.lineno,
    colno: event.colno,
    stack: event.error?.stack,
  };

  // 发送错误信息
  navigator.sendBeacon("/error", JSON.stringify(error));
});

// 3. 资源加载监控
const resourceObserver = new PerformanceObserver((list) => {
  list.getEntries().forEach((entry) => {
    if (entry.initiatorType === "img" || entry.initiatorType === "script") {
      console.log(`${entry.name} loaded in: ${entry.duration}ms`);
    }
  });
});

resourceObserver.observe({ entryTypes: ["resource"] });

2. 加载优化

懒加载实现

// 1. 组件懒加载
const LazyComponent = React.lazy(() => import("./LazyComponent"));

function App() {
  return (
    <Suspense fallback={<Loading />}>
      <LazyComponent />
    </Suspense>
  );
}

// 2. 路由懒加载
const routes = [
  {
    path: "/dashboard",
    component: () => import("./views/Dashboard"),
  },
];

// 3. 图片懒加载
function LazyImage({ src, alt }) {
  const [isLoaded, setIsLoaded] = useState(false);
  const imgRef = useRef();

  useEffect(() => {
    const observer = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting) {
        setIsLoaded(true);
        observer.disconnect();
      }
    });

    observer.observe(imgRef.current);
    return () => observer.disconnect();
  }, []);

  return (
    <img ref={imgRef} src={isLoaded ? src : "placeholder.jpg"} alt={alt} />
  );
}

预加载策略

// 1. 资源预加载
document.head.appendChild(Object.assign(
  document.createElement('link'),
  {
    rel: 'preload',
    href: 'heavy-component.js',
    as: 'script'
  }
));

// 2. DNS预解析
<link rel="dns-prefetch" href="//example.com">

// 3. 预连接
<link rel="preconnect" href="https://example.com">

// 4. 条件预加载
const prefetchComponent = () => {
  const link = document.createElement('link');
  link.rel = 'prefetch';
  link.href = '/component.js';
  document.head.appendChild(link);
};

// 在空闲时预加载
if (requestIdleCallback) {
  requestIdleCallback(prefetchComponent);
} else {
  setTimeout(prefetchComponent, 1000);
}

缓存优化

// 1. Service Worker 缓存
// sw.js
const CACHE_NAME = 'v1';
const urlsToCache = [
  '/',
  '/styles.css',
  '/app.js'
];

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(cache => cache.addAll(urlsToCache))
  );
});

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(response => {
        if (response) {
          return response;
        }
        return fetch(event.request).then(
          response => {
            if (!response || response.status !== 200) {
              return response;
            }
            const responseToCache = response.clone();
            caches.open(CACHE_NAME)
              .then(cache => {
                cache.put(event.request, responseToCache);
              });
            return response;
          }
        );
      })
  );
});

// 2. HTTP 缓存配置
// Nginx配置
location /static/ {
  expires 1y;
  add_header Cache-Control "public, no-transform";
}

// 3. 内存缓存
const cache = new Map();

function memoize(fn) {
  return function (...args) {
    const key = JSON.stringify(args);
    if (cache.has(key)) {
      return cache.get(key);
    }
    const result = fn.apply(this, args);
    cache.set(key, result);
    return result;
  };
}

最后更新于

这有帮助吗?