啥是 LCP

最大内容绘制。
image.png

旧指标

  • load 和 DOMContentLoaded 不一定和用户看到屏幕对应
  • FCP 只能捕捉到加载的最开始
  • 过去也推荐 FMP first meaningful paint 和 SI speed index,来获取fp之后的加载性能,但过于复杂(赞同)和容易出错,没办法主要内容合适加载完成。
  • 所以简单点,最大块的内容渲染完,基本主体内容就加载完了。

判断条件

和 lcp api 有关。

LCP - Largest Contentful Paint - 图2 元素
LCP - Largest Contentful Paint - 图3元素内的元素

元素(使用海报图像)通过url()函数加载背景图片的元素 (与CSS渐变相反 )包含文本节点或其他内联级文本元素子级的块级元素。

实现方法

最简单的还是加载 库

  1. // 定义变量
  2. let firstHiddenTime = document.visibilityState === 'hidden' ? 0 : Infinity;
  3. // 监听变量
  4. document.addEventListener('visibilitychange', (event) => {
  5. firstHiddenTime = Math.min(firstHiddenTime, event.timeStamp);
  6. }, {once: true});
  7. // send
  8. function sendToAnalytics(data) {
  9. const body = JSON.stringify(data);
  10. // Use `navigator.sendBeacon()` if available, falling back to `fetch()`.
  11. (navigator.sendBeacon && navigator.sendBeacon('/analytics', body)) ||
  12. fetch('/analytics', {body, method: 'POST', keepalive: true});
  13. }
  14. try {
  15. // 创建一个变量
  16. let lcp;
  17. function updateLCP(entry) {
  18. // Only include an LCP entry if the page wasn't hidden prior to
  19. // the entry being dispatched. This typically happens when a page is
  20. // loaded in a background tab.
  21. if (entry.startTime < firstHiddenTime) {
  22. // NOTE: the `startTime` value is a getter that returns the entry's
  23. // `renderTime` value, if available, or its `loadTime` value otherwise.
  24. // The `renderTime` value may not be available if the element is an image
  25. // that's loaded cross-origin without the `Timing-Allow-Origin` header.
  26. lcp = entry.startTime;
  27. }
  28. }
  29. // Create a PerformanceObserver that calls `updateLCP` for each entry.
  30. const po = new PerformanceObserver((entryList, po) => {
  31. entryList.getEntries().forEach((entry) => updateLCP(entry, po));
  32. });
  33. // 监听 largest-contentful-paint
  34. po.observe({
  35. type: 'largest-contentful-paint',
  36. buffered: true,
  37. });
  38. // Log the final LCP score once the
  39. // page's lifecycle state changes to hidden.
  40. addEventListener('visibilitychange', function fn(event) {
  41. if (document.visibilityState === 'hidden') {
  42. removeEventListener('visibilitychange', fn, true);
  43. // Force any pending records to be dispatched and disconnect the observer.
  44. po.takeRecords().forEach((entry) => updateLCP(entry, po));
  45. po.disconnect();
  46. // If LCP is set, report it to an analytics endpoint.
  47. if (lcp) {
  48. sendToAnalytics({lcp});
  49. }
  50. }
  51. }, true);
  52. } catch (e) {
  53. // Do nothing if the browser doesn't support this API.
  54. }

参考资料