这篇文章笔记来自 https://web.dev/fcp/ ,之后的FCP内容会补充到这里。

建议自行阅读,以便更好地理解。

FCP是一个性能指标,直译是 第一次有内容的绘制,和之前的 firstPaint相比,多了一个 contentful ,如何判断有内容的。

啥是FCP

定义

假定有下面的页面渲染流程截图:
image.png

这里的 contentful 是指

  • 文本、
  • img图像、
  • url()背景图像、
  • svg元素,
  • video元素,如果定义cover会影响lcp
  • 非白色的canvas元素

目前是这样的规则,后续可能会更新。

需要注意的是,如果用户打开页面之后,切换到后台,等再次回到前台的时候,用户产生了交互行为,该埋点就不准确了,会比真实的时间延长一些。

上图中fcp是第二帧,也会发现,这里的 first 是指第一次,并不表示页面完全渲染,页面完全渲染用到的指标是 LCP

如何测量FCP

我们可以通过之前提到的npm包来完成计算 web-vitals ,如何手动测量?这里需要用到 paint timign api

我解释下面的代码

  1. // Keep track of whether (and when) the page was first hidden, see:
  2. // https://github.com/w3c/page-visibility/issues/29
  3. // NOTE: ideally this check would be performed in the document <head>
  4. // to avoid cases where the visibility state changes before this code runs.
  5. // 先定义变量,当前文档是的 visibilityState
  6. let firstHiddenTime = document.visibilityState === 'hidden' ? 0 : Infinity;
  7. // 后面进行监听事件
  8. document.addEventListener('visibilitychange', (event) => {
  9. firstHiddenTime = Math.min(firstHiddenTime, event.timeStamp);
  10. }, {once: true});
  11. // 这里把信息通过 sendBeacon 发送
  12. function sendToAnalytics(data) {
  13. const body = JSON.stringify(data);
  14. // Use `navigator.sendBeacon()` if available, falling back to `fetch()`.
  15. (navigator.sendBeacon && navigator.sendBeacon('/analytics', body)) ||
  16. fetch('/analytics', {body, method: 'POST', keepalive: true});
  17. }
  18. // 使用 try catch包装
  19. try {
  20. // 定义函数
  21. function onPaintEntry(entry, po) {
  22. // 只关注fcp
  23. if (entry.name === 'first-contentful-paint' &&
  24. entry.startTime < firstHiddenTime) {
  25. // Disconnect the observer.
  26. po.disconnect();
  27. // Report the FCP value to an analytics endpoint.
  28. sendToAnalytics({fcp: entry.startTime});
  29. }
  30. }
  31. // 创建一个 PerformanceObserver 调用 `onPaintEntry` for each entry.
  32. const po = new PerformanceObserver((entryList, po) => {
  33. entryList.getEntries().forEach((entry) => onPaintEntry(entry, po));
  34. });
  35. // Observe entries of type `paint`, including buffered entries,
  36. // i.e. entries that occurred before calling `observe()` below.
  37. po.observe({
  38. type: 'paint',
  39. buffered: true,
  40. });
  41. } catch (e) {
  42. // Do nothing if the browser doesn't support this API.
  43. }

关于对 PerformanceObserver 有进一步的使用和说明。

FCP的衡量标准

应当在1s内。75%

比如我们要承诺 99% 的用户都要小于 5 秒,我们看页面加载时长时候就应该看 99 分位数。如果我们现在精力不够,我们只能承诺 50% 的人页面加载时长小于 5 秒,实际上 50 分位数,就是中位数,就是 50% 的访问能够不小于这个时间打开这个页面。

如何优化FCP

消除渲染阻止资源
缩小CSS
删除未使用的CSS
预连接到所需的起点
减少服务器响应时间(TTFB)
避免多次页面重定向
预加载关键请求
避免大量的网络负载
通过有效的缓存策略服务静态资产
避免DOM太大
最小化关键请求深度
确保文本在Webfont加载期间保持可见
保持较低的请求数量和较小的传输量