getLCP.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. /*
  2. * Copyright 2020 Google LLC
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * https://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. import { bindReporter } from './lib/bindReporter.js';
  17. import { finalMetrics } from './lib/finalMetrics.js';
  18. import { getFirstHidden } from './lib/getFirstHidden.js';
  19. import { initMetric } from './lib/initMetric.js';
  20. import { observe } from './lib/observe.js';
  21. import { onBFCacheRestore } from './lib/onBFCacheRestore.js';
  22. import { onHidden } from './lib/onHidden.js';
  23. export const getLCP = (onReport, reportAllChanges) => {
  24. const firstHidden = getFirstHidden();
  25. let metric = initMetric('LCP');
  26. let report;
  27. const entryHandler = (entry) => {
  28. // The startTime attribute returns the value of the renderTime if it is not 0,
  29. // and the value of the loadTime otherwise.
  30. const value = entry.startTime;
  31. // If the page was hidden prior to paint time of the entry,
  32. // ignore it and mark the metric as final, otherwise add the entry.
  33. if (value < firstHidden.timeStamp) {
  34. metric.value = value;
  35. metric.entries.push(entry);
  36. }
  37. report();
  38. };
  39. const po = observe('largest-contentful-paint', entryHandler);
  40. if (po) {
  41. report = bindReporter(onReport, metric, reportAllChanges);
  42. const stopListening = () => {
  43. if (!finalMetrics.has(metric)) {
  44. po.takeRecords().map(entryHandler);
  45. po.disconnect();
  46. finalMetrics.add(metric);
  47. report();
  48. }
  49. };
  50. // Stop listening after input. Note: while scrolling is an input that
  51. // stop LCP observation, it's unreliable since it can be programmatically
  52. // generated. See: https://github.com/GoogleChrome/web-vitals/issues/75
  53. ['keydown', 'click'].forEach((type) => {
  54. addEventListener(type, stopListening, { once: true, capture: true });
  55. });
  56. onHidden(stopListening, true);
  57. onBFCacheRestore((event) => {
  58. metric = initMetric('LCP');
  59. report = bindReporter(onReport, metric, reportAllChanges);
  60. requestAnimationFrame(() => {
  61. requestAnimationFrame(() => {
  62. metric.value = performance.now() - event.timeStamp;
  63. finalMetrics.add(metric);
  64. report();
  65. });
  66. });
  67. });
  68. }
  69. };