getLCP.js 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import { bindReporter } from './lib/bindReporter.js';
  2. import { getActivationStart } from './lib/getActivationStart.js';
  3. import { getVisibilityWatcher } from './lib/getVisibilityWatcher.js';
  4. import { initMetric } from './lib/initMetric.js';
  5. import { observe } from './lib/observe.js';
  6. import { onHidden } from './lib/onHidden.js';
  7. /*
  8. * Copyright 2020 Google LLC
  9. *
  10. * Licensed under the Apache License, Version 2.0 (the "License");
  11. * you may not use this file except in compliance with the License.
  12. * You may obtain a copy of the License at
  13. *
  14. * https://www.apache.org/licenses/LICENSE-2.0
  15. *
  16. * Unless required by applicable law or agreed to in writing, software
  17. * distributed under the License is distributed on an "AS IS" BASIS,
  18. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  19. * See the License for the specific language governing permissions and
  20. * limitations under the License.
  21. */
  22. const reportedMetricIDs = {};
  23. /**
  24. * Calculates the [LCP](https://web.dev/lcp/) value for the current page and
  25. * calls the `callback` function once the value is ready (along with the
  26. * relevant `largest-contentful-paint` performance entry used to determine the
  27. * value). The reported value is a `DOMHighResTimeStamp`.
  28. */
  29. const onLCP = (onReport) => {
  30. const visibilityWatcher = getVisibilityWatcher();
  31. const metric = initMetric('LCP');
  32. let report;
  33. const handleEntries = (entries) => {
  34. const lastEntry = entries[entries.length - 1] ;
  35. if (lastEntry) {
  36. // The startTime attribute returns the value of the renderTime if it is
  37. // not 0, and the value of the loadTime otherwise. The activationStart
  38. // reference is used because LCP should be relative to page activation
  39. // rather than navigation start if the page was prerendered.
  40. const value = Math.max(lastEntry.startTime - getActivationStart(), 0);
  41. // Only report if the page wasn't hidden prior to LCP.
  42. if (value < visibilityWatcher.firstHiddenTime) {
  43. metric.value = value;
  44. metric.entries = [lastEntry];
  45. report();
  46. }
  47. }
  48. };
  49. const po = observe('largest-contentful-paint', handleEntries);
  50. if (po) {
  51. report = bindReporter(onReport, metric);
  52. const stopListening = () => {
  53. if (!reportedMetricIDs[metric.id]) {
  54. handleEntries(po.takeRecords() );
  55. po.disconnect();
  56. reportedMetricIDs[metric.id] = true;
  57. report(true);
  58. }
  59. };
  60. // Stop listening after input. Note: while scrolling is an input that
  61. // stop LCP observation, it's unreliable since it can be programmatically
  62. // generated. See: https://github.com/GoogleChrome/web-vitals/issues/75
  63. ['keydown', 'click'].forEach(type => {
  64. addEventListener(type, stopListening, { once: true, capture: true });
  65. });
  66. onHidden(stopListening, true);
  67. return stopListening;
  68. }
  69. return;
  70. };
  71. export { onLCP };
  72. //# sourceMappingURL=getLCP.js.map