API Frame Animasi Panjang

Long Animation Frames API (LoAF-dibaca Lo-Af) adalah update untuk Long Tasks API guna memberikan pemahaman yang lebih baik tentang update antarmuka pengguna (UI) yang lambat. Hal ini dapat berguna untuk mengidentifikasi frame animasi lambat yang cenderung memengaruhi metrik Core Web Vitals Interaction to Next Paint (INP) yang mengukur responsivitas, atau untuk mengidentifikasi jank UI lainnya yang memengaruhi kehalusan.

Status API

Dukungan Browser

  • Chrome: 123.
  • Edge: 123.
  • Firefox: tidak didukung.
  • Safari: tidak didukung.

Sumber

Setelah uji coba origin dari Chrome 116 ke Chrome 122, LoAF API telah dikirim dari Chrome 123.

Latar belakang: Long Tasks API

Dukungan Browser

  • Chrome: 58.
  • Edge: 79.
  • Firefox: tidak didukung.
  • Safari: tidak didukung.

Sumber

Long Animation Frames API adalah alternatif untuk Long Tasks API yang telah tersedia di Chrome sejak beberapa waktu lalu (sejak Chrome 58). Seperti namanya, Long Task API memungkinkan Anda memantau tugas panjang, yaitu tugas yang menempati thread utama selama 50 milidetik atau lebih lama. Tugas yang lama dapat dipantau menggunakan antarmuka PerformanceLongTaskTiming, dengan PeformanceObserver:

const observer = new PerformanceObserver((list) => {
  console.log(list.getEntries());
});

observer.observe({ type: 'longtask', buffered: true });

Tugas yang lama kemungkinan akan menyebabkan masalah responsivitas. Jika pengguna mencoba berinteraksi dengan halaman—misalnya, mengklik tombol, atau membuka menu—tetapi thread utama sudah menangani tugas yang lama, interaksi pengguna akan tertunda menunggu tugas tersebut selesai.

Untuk meningkatkan responsivitas, sebaiknya bagi tugas yang panjang. Jika setiap tugas panjang dibagi menjadi serangkaian beberapa tugas yang lebih kecil, tugas yang lebih penting dapat dijalankan di antara tugas tersebut untuk menghindari penundaan yang signifikan dalam merespons interaksi.

Jadi, saat mencoba meningkatkan responsivitas, upaya pertama sering kali adalah menjalankan pelacakan performa dan melihat tugas yang lama. Hal ini dapat dilakukan melalui alat audit berbasis lab seperti Lighthouse (yang memiliki audit Menghindari tugas thread utama yang berjalan lama), atau dengan melihat tugas yang berjalan lama di Chrome DevTools.

Pengujian berbasis lab sering kali bukan tempat yang tepat untuk mengidentifikasi masalah responsivitas, karena alat ini mungkin tidak menyertakan interaksi—jika ada, alat ini adalah sebagian kecil dari kemungkinan interaksi. Idealnya, Anda akan mengukur penyebab interaksi yang lambat di lapangan.

Kekurangan Long Tasks API

Mengukur tugas yang lama di lapangan menggunakan Performance Observer hanya sedikit berguna. Pada kenyataannya, informasi yang diberikan tidak terlalu banyak selain fakta bahwa tugas yang lama terjadi, dan berapa lama waktu yang diperlukan.

Alat Real User Monitoring (RUM) sering kali menggunakan ini untuk membuat tren jumlah atau durasi tugas yang lama atau mengidentifikasi halaman tempat tugas tersebut terjadi—tetapi tanpa detail mendasar tentang penyebab tugas yang lama, penggunaannya hanya terbatas. Long Tasks API hanya memiliki model atribusi dasar, yang paling baik hanya memberi tahu Anda penampung tempat tugas panjang terjadi (dokumen tingkat atas atau <iframe>), tetapi bukan skrip atau fungsi yang memanggilnya, seperti yang ditunjukkan oleh entri standar:

{
  "name": "unknown",
  "entryType": "longtask",
  "startTime": 31.799999997019768,
  "duration": 136,
  "attribution": [
    {
      "name": "unknown",
      "entryType": "taskattribution",
      "startTime": 0,
      "duration": 0,
      "containerType": "window",
      "containerSrc": "",
      "containerId": "",
      "containerName": ""
    }
  ]
}

Long Tasks API juga merupakan tampilan yang tidak lengkap, karena dapat juga mengecualikan beberapa tugas penting. Beberapa pembaruan—seperti rendering—terjadi dalam tugas terpisah yang idealnya harus disertakan bersama dengan eksekusi sebelumnya yang menyebabkan pembaruan tersebut mengukur "total pekerjaan" untuk interaksi tersebut secara akurat. Untuk mengetahui detail selengkapnya tentang batasan mengandalkan tugas, lihat bagian "Kekurangan tugas yang lama" dalam penjelasan.

Masalah terakhir adalah pengukuran tugas yang lama hanya melaporkan tugas individual yang memerlukan waktu lebih dari batas 50 milidetik. Frame animasi dapat terdiri dari beberapa tugas yang lebih kecil dari batas 50 milidetik ini, tetapi secara kolektif masih memblokir kemampuan browser untuk merender.

Long Animation Frames API

Dukungan Browser

  • Chrome: 123.
  • Edge: 123.
  • Firefox: tidak didukung.
  • Safari: tidak didukung.

Sumber

Long Animation Frames API (LoAF) adalah API baru yang berupaya mengatasi beberapa kekurangan Long Tasks API agar developer dapat memperoleh insight yang lebih bisa ditindaklanjuti untuk membantu mengatasi masalah responsivitas dan meningkatkan INP, serta mendapatkan insight tentang masalah kelancaran.

Responsivitas yang baik berarti halaman merespons dengan cepat interaksi yang dilakukan dengannya. Hal ini mencakup kemampuan untuk menggambar update apa pun yang diperlukan pengguna secara tepat waktu, dan menghindari pemblokiran update ini. Untuk INP, sebaiknya respons dalam waktu 200 milidetik atau kurang, tetapi untuk update lainnya (misalnya, animasi), bahkan 200 milidetik mungkin terlalu lama.

Long Animation Frames API adalah pendekatan alternatif untuk mengukur pekerjaan pemblokiran. Alih-alih mengukur setiap tugas, Long Animation Frames API—seperti namanya—mengukur frame animasi panjang. Frame animasi yang lama adalah saat update rendering tertunda lebih dari 50 milidetik (sama dengan nilai minimum untuk Long Tasks API).

Frame animasi panjang diukur dari awal tugas yang memerlukan rendering. Jika tugas pertama dalam potensi frame animasi panjang tidak memerlukan rendering, frame animasi panjang akan berakhir setelah tugas non-rendering selesai dan potensi frame animasi panjang baru dimulai dengan tugas berikutnya. Frame animasi panjang yang tidak dirender tersebut masih disertakan dalam Long Animation Frames API jika lebih besar dari 50 milidetik (dengan waktu renderStart 0) untuk memungkinkan pengukuran pekerjaan yang berpotensi memblokir.

Frame animasi yang panjang dapat diamati dengan cara yang sama seperti tugas panjang dengan PerformanceObserver, tetapi dengan melihat jenis long-animation-frame:

const observer = new PerformanceObserver((list) => {
  console.log(list.getEntries());
});

observer.observe({ type: 'long-animation-frame', buffered: true });

Frame animasi panjang sebelumnya juga dapat dikueri dari Linimasa Performa seperti ini:

const loafs = performance.getEntriesByType('long-animation-frame');

Namun, ada maxBufferSize untuk entri performa, setelah itu entri yang lebih baru akan dihapus, sehingga pendekatan PerformanceObserver adalah pendekatan yang direkomendasikan. Ukuran buffer long-animation-frame ditetapkan ke 200, sama seperti untuk long-tasks.

Keunggulan melihat frame, bukan tugas

Keuntungan utama melihat hal ini dari perspektif frame, bukan perspektif tugas, adalah animasi panjang dapat terdiri dari sejumlah tugas yang secara kumulatif menghasilkan frame animasi panjang. Hal ini membahas poin terakhir yang disebutkan sebelumnya, yaitu jumlah banyak tugas pemblokir render yang lebih kecil sebelum frame animasi mungkin tidak ditampilkan oleh Long Tasks API.

Keuntungan lebih lanjut dari tampilan alternatif ini pada tugas yang lama adalah kemampuan untuk memberikan perincian pengaturan waktu seluruh frame. Daripada hanya menyertakan startTime dan duration, seperti Long Tasks API, LoAF menyertakan perincian yang jauh lebih mendetail tentang berbagai bagian durasi frame.

Stempel waktu dan durasi frame

  • startTime: waktu mulai frame animasi panjang relatif terhadap waktu mulai navigasi.
  • duration: durasi frame animasi panjang (tidak termasuk waktu presentasi).
  • renderStart: waktu mulai siklus rendering, yang mencakup callback requestAnimationFrame, penghitungan gaya dan tata letak, callback observer perubahan ukuran, dan callback observer persimpangan.
  • styleAndLayoutStart: awal jangka waktu yang dihabiskan dalam penghitungan gaya dan tata letak.
  • firstUIEventTimestamp: waktu peristiwa UI pertama (mouse/keyboard dan sebagainya) yang akan ditangani selama frame ini.
  • blockingDuration: total durasi dalam milidetik yang digunakan frame animasi untuk memblokir pemrosesan input atau tugas prioritas tinggi lainnya.

Penjelasan blockingDuration

Frame animasi yang panjang dapat terdiri dari sejumlah tugas. blockingDuration adalah jumlah durasi tugas yang lebih dari 50 milidetik (termasuk durasi rendering akhir dalam tugas terpanjang).

Misalnya, jika frame animasi panjang terdiri dari dua tugas berdurasi 55 milidetik dan 65 milidetik, diikuti dengan rendering berdurasi 20 milidetik, duration akan menjadi sekitar 140 milidetik dengan blockingDuration sebesar (55 - 50) + (65 + 20 - 50) = 40 milidetik. Selama 40 milidetik selama frame animasi berdurasi 140 milidetik ini, frame dianggap diblokir agar tidak menangani input.

Apakah akan melihat duration atau blockingDuration

Untuk tampilan 60 hertz umum, browser akan mencoba menjadwalkan frame setidaknya setiap 16,66 milidetik (untuk memastikan update yang lancar), atau setelah tugas prioritas tinggi seperti penanganan input (untuk memastikan update yang responsif). Namun, jika tidak ada input—atau tugas prioritas tinggi lainnya—tetapi ada antrean tugas lain, browser biasanya akan melanjutkan frame saat ini jauh setelah 16,66 milidetik, terlepas dari seberapa baik tugas tersebut dibagi di dalamnya. Artinya, browser akan selalu mencoba memprioritaskan input, tetapi dapat memilih untuk menangani antrean tugas melalui update render. Hal ini karena rendering adalah proses yang mahal sehingga memproses tugas rendering gabungan untuk beberapa tugas biasanya akan mengurangi pekerjaan secara keseluruhan.

Oleh karena itu, frame animasi yang panjang dengan blockingDuration rendah atau nol akan tetap terasa responsif terhadap input. Oleh karena itu, mengurangi atau menghilangkan blockingDuration dengan membagi tugas yang panjang adalah kunci untuk meningkatkan responsivitas seperti yang diukur oleh INP.

Namun, banyak frame animasi yang panjang, terlepas dari blockingDuration, menunjukkan update UI yang tertunda sehingga masih dapat memengaruhi kelancaran dan menyebabkan perasaan antarmuka pengguna yang lambat untuk men-scroll atau animasi, meskipun hal ini kurang menjadi masalah untuk responsivitas seperti yang diukur oleh INP. Untuk memahami masalah di area ini, lihat duration, tetapi hal ini mungkin lebih sulit dioptimalkan karena Anda tidak dapat menyelesaikannya dengan membagi pekerjaan, tetapi harus mengurangi pekerjaan.

Pengaturan waktu frame

Stempel waktu yang disebutkan sebelumnya memungkinkan frame animasi panjang dibagi menjadi pengaturan waktu:

Waktu Penghitungan
Waktu Mulai startTime
Waktu Berakhir startTime + duration
Durasi kerja renderStart ? renderStart - startTime : duration
Durasi render renderStart ? (startTime + duration) - renderStart: 0
Render: Durasi pra-tata letak styleAndLayoutStart ? styleAndLayoutStart - renderStart : 0
Render: Durasi Gaya dan Tata Letak styleAndLayoutStart ? (startTime + duration) - styleAndLayoutStart : 0

Atribusi skrip yang lebih baik

Jenis entri long-animation-frame menyertakan data atribusi yang lebih baik dari setiap skrip yang berkontribusi pada frame animasi yang panjang (untuk skrip yang lebih dari 5 milidetik).

Serupa dengan Long Tasks API, data ini akan disediakan dalam array entri atribusi, yang masing-masing menjelaskan:

  • name dan EntryType akan menampilkan script.
  • invoker yang bermakna, yang menunjukkan cara skrip dipanggil (misalnya, 'IMG#id.onload', 'Window.requestAnimationFrame', atau 'Response.json.then').
  • invokerType titik entri skrip:
    • user-callback: Callback yang diketahui terdaftar dari API platform web (misalnya, setTimeout, requestAnimationFrame).
    • event-listener: Pemroses peristiwa platform (misalnya, click, load, keyup).
    • resolve-promise: Pengendali promise platform (misalnya, fetch(). Perhatikan bahwa dalam kasus promise, semua pengendali promise yang sama digabungkan menjadi satu "skrip").
    • reject-promise: Seperti resolve-promise, tetapi untuk penolakan.
    • classic-script: Evaluasi skrip (misalnya, <script> atau import())
    • module-script: Sama seperti classic-script, tetapi untuk skrip modul.
  • Data pengaturan waktu terpisah untuk skrip tersebut:
    • startTime: Waktu fungsi entri dipanggil.
    • duration: Durasi antara startTime dan saat antrean microtask berikutnya selesai diproses.
    • executionStart: Waktu setelah kompilasi.
    • forcedStyleAndLayoutDuration: Total waktu yang dihabiskan untuk memproses tata letak dan gaya paksa di dalam fungsi ini (lihat thrashing).
    • pauseDuration: Total waktu yang dihabiskan untuk "menjeda" operasi sinkron (notifikasi, XHR sinkron).
  • Detail sumber skrip:
    • sourceURL: Nama resource skrip jika tersedia (atau kosong jika tidak ditemukan).
    • sourceFunctionName: Nama fungsi skrip jika tersedia (atau kosong jika tidak ditemukan).
    • sourceCharPosition: Posisi karakter skrip jika tersedia (atau -1 jika tidak ditemukan).
  • windowAttribution: Penampung (dokumen tingkat teratas, atau <iframe>) tempat frame animasi panjang terjadi.
  • window: Referensi ke jendela dengan origin yang sama.

Jika disediakan, entri sumber memungkinkan developer mengetahui dengan tepat bagaimana setiap skrip dalam frame animasi panjang dipanggil, hingga posisi karakter dalam skrip panggilan. Hal ini memberikan lokasi yang tepat dalam resource JavaScript yang menghasilkan frame animasi yang panjang.

Contoh entri performa long-animation-frame

Contoh entri performa long-animation-frame lengkap, yang berisi satu skrip, adalah:

{
  "blockingDuration": 0,
  "duration": 60,
  "entryType": "long-animation-frame",
  "firstUIEventTimestamp": 11801.099999999627,
  "name": "long-animation-frame",
  "renderStart": 11858.800000000745,
  "scripts": [
    {
      "duration": 45,
      "entryType": "script",
      "executionStart": 11803.199999999255,
      "forcedStyleAndLayoutDuration": 0,
      "invoker": "DOMWindow.onclick",
      "invokerType": "event-listener",
      "name": "script",
      "pauseDuration": 0,
      "sourceURL": "https://web.dev/js/index-ffde4443.js",
      "sourceFunctionName": "myClickHandler",
      "sourceCharPosition": 17796,
      "startTime": 11803.199999999255,
      "window": [Window object],
      "windowAttribution": "self"
    }
  ],
  "startTime": 11802.400000000373,
  "styleAndLayoutStart": 11858.800000000745
}

Seperti yang dapat dilihat, hal ini memberikan jumlah data yang belum pernah ada sebelumnya bagi situs untuk dapat memahami penyebab pembaruan rendering yang lambat.

Menggunakan Long Animation Frames API di lapangan

Alat seperti Chrome DevTools dan Lighthouse—meskipun berguna untuk menemukan dan mereproduksi masalah—adalah alat lab yang mungkin melewatkan aspek penting dari pengalaman pengguna yang hanya dapat diberikan oleh data lapangan.

Long Animation Frames API dirancang untuk digunakan di lapangan guna mengumpulkan data kontekstual penting untuk interaksi pengguna yang tidak dapat dilakukan oleh Long Tasks API. Hal ini dapat membantu Anda mengidentifikasi dan mereproduksi masalah interaktivitas yang mungkin tidak Anda temukan.

Dukungan API Long Animation Frames yang mendeteksi fitur

Anda dapat menggunakan kode berikut untuk menguji apakah API didukung:

if (PerformanceObserver.supportedEntryTypes.includes('long-animation-frame')) {
  // Monitor LoAFs
}

Kasus penggunaan yang paling jelas untuk Long Animation Frames API adalah untuk membantu mendiagnosis dan memperbaiki masalah Interaction to Next Paint (INP), dan itulah salah satu alasan utama tim Chrome mengembangkan API ini. INP yang baik adalah tempat semua interaksi direspons dalam 200 milidetik atau kurang dari interaksi hingga frame digambar, dan karena Long Animation Frames API mengukur semua frame yang memerlukan waktu 50 md atau lebih, sebagian besar INP yang bermasalah harus menyertakan data LoAF untuk membantu Anda mendiagnosis interaksi tersebut.

"INP LoAF" adalah LoAF yang menyertakan interaksi INP, seperti yang ditunjukkan dalam diagram berikut:

Contoh frame animasi panjang di halaman, dengan INP LoAF ditandai.
Satu halaman dapat memiliki banyak LoAF, salah satunya terkait dengan interaksi INP.

Dalam beberapa kasus, peristiwa INP dapat mencakup dua LoAF—biasanya jika interaksi terjadi setelah frame memulai bagian rendering dari frame sebelumnya, sehingga pengendali peristiwa diproses di frame berikutnya:

Contoh frame animasi panjang di halaman, dengan INP LoAF ditandai.
Satu halaman dapat memiliki banyak LoAF, salah satunya terkait dengan interaksi INP.

Bahkan, dalam beberapa kasus yang jarang terjadi, LoAF dapat mencakup lebih dari dua LoAF.

Dengan merekam data LoAF yang terkait dengan interaksi INP, Anda bisa mendapatkan lebih banyak informasi tentang interaksi INP untuk membantu mendiagnosisnya. Hal ini sangat membantu untuk memahami input delay: karena Anda dapat melihat skrip lain yang berjalan dalam frame tersebut.

Anda juga dapat memahami durasi pemrosesan dan penundaan presentasi yang tidak dapat dijelaskan jika pengendali peristiwa Anda tidak mereproduksi nilai yang terlihat untuk peristiwa tersebut karena skrip lain mungkin berjalan untuk pengguna Anda yang mungkin tidak disertakan dalam pengujian Anda sendiri.

Tidak ada API langsung untuk menautkan entri INP dengan entri LoAF terkait, meskipun Anda dapat melakukannya dalam kode dengan membandingkan waktu mulai dan waktu berakhir masing-masing (lihat WhyNp). Library web-vitals menyertakan semua LoAF yang berpotongan di properti longAnimationFramesEntries antarmuka atribusi INP dari v4.

Setelah menautkan entri LoAF, Anda dapat menyertakan informasi dengan atribusi INP. Objek scripts berisi beberapa informasi paling berharga karena dapat menunjukkan hal lain yang berjalan dalam frame tersebut sehingga dengan mengirimkan kembali data tersebut ke layanan analisis, Anda dapat lebih memahami alasan interaksi lambat.

Melaporkan LoAF untuk interaksi INP adalah cara yang baik untuk menemukan masalah interaktivitas yang paling mendesak di halaman Anda. Setiap pengguna mungkin berinteraksi dengan halaman Anda secara berbeda dan dengan volume data atribusi INP yang cukup, sejumlah potensi masalah akan disertakan dalam data atribusi INP. Dengan begitu, Anda dapat mengurutkan skrip berdasarkan volume untuk melihat skrip mana yang berkorelasi dengan INP lambat.

Melaporkan lebih banyak data animasi panjang kembali ke endpoint analisis

Salah satu kelemahan dari hanya melihat LoAF INP adalah Anda mungkin melewatkan potensi area lain untuk peningkatan yang dapat menyebabkan masalah INP di masa mendatang. Hal ini dapat menyebabkan perasaan seperti mengejar ekor sendiri saat Anda memperbaiki masalah INP dan berharap akan melihat peningkatan yang besar, tetapi ternyata interaksi terlama berikutnya hanya sedikit lebih baik dari sebelumnya sehingga INP Anda tidak banyak meningkat.

Jadi, daripada hanya melihat LoAF INP, sebaiknya pertimbangkan semua LoAF selama masa aktif halaman:

Halaman dengan banyak LoAF, beberapa di antaranya terjadi selama interaksi meskipun bukan interaksi INP.
Mengamati semua LoAF dapat membantu mengidentifikasi masalah INP di masa mendatang.

Namun, setiap entri LoAF berisi data yang cukup besar, sehingga Anda mungkin ingin membatasi analisis hanya pada beberapa LoAF. Selain itu, karena entri frame animasi yang panjang dapat berukuran cukup besar, developer harus memutuskan data apa dari entri yang akan dikirim ke analisis. Misalnya, waktu ringkasan entri dan mungkin nama skrip, atau beberapa kumpulan minimum data kontekstual lainnya yang mungkin dianggap perlu.

Beberapa pola yang disarankan untuk mengurangi jumlah data frame animasi yang panjang meliputi:

Manakah dari pola ini yang paling sesuai untuk Anda, bergantung pada seberapa jauh Anda telah melakukan perjalanan pengoptimalan, dan seberapa umum frame animasi panjang. Untuk situs yang belum pernah mengoptimalkan responsivitas sebelumnya, mungkin ada banyak LoAF. Sebaiknya Anda membatasi LoAF hanya dengan interaksi, atau menetapkan nilai minimum yang tinggi, atau hanya melihat LoAF yang terburuk.

Saat menyelesaikan masalah responsivitas umum, Anda dapat memperluasnya dengan tidak membatasi hanya interaksi atau durasi pemblokiran yang tinggi atau dengan menurunkan nilai minimum.

Mengamati frame animasi panjang dengan interaksi

Untuk mendapatkan insight di luar frame animasi panjang INP, Anda dapat melihat semua LoAF dengan interaksi (yang dapat dideteksi dengan adanya nilai firstUIEventTimestamp) dengan blockingDuration yang tinggi.

Ini juga dapat menjadi metode yang lebih mudah untuk memantau LoAF INP, bukan mencoba mengorelasi keduanya, yang dapat lebih kompleks. Dalam sebagian besar kasus, hal ini akan mencakup LoAF INP untuk kunjungan tertentu, dan dalam kasus yang jarang terjadi, jika tidak, interaksi panjang yang penting untuk diperbaiki masih akan ditampilkan, karena mungkin merupakan interaksi INP untuk pengguna lain.

Kode berikut mencatat semua entri LoAF dengan blockingDuration lebih dari 100 milidetik saat interaksi terjadi selama frame. Nilai 100 dipilih di sini karena kurang dari nilai minimum INP "baik" 200 milidetik. Anda dapat memilih nilai yang lebih tinggi atau lebih rendah bergantung pada kebutuhan Anda.

const REPORTING_THRESHOLD_MS = 100;

const observer = new PerformanceObserver(list => {
  for (const entry of list.getEntries()) {
    if (entry.blockingDuration > REPORTING_THRESHOLD_MS &&
      entry.firstUIEventTimestamp > 0
    ) {
      // Example here logs to console, but could also report back to analytics
      console.log(entry);
    }
  }
});
observer.observe({ type: 'long-animation-frame', buffered: true });

Mengamati frame animasi panjang dengan durasi pemblokiran tinggi

Sebagai peningkatan untuk melihat semua frame animasi panjang dengan interaksi, sebaiknya lihat semua frame animasi panjang dengan durasi pemblokiran tinggi. Hal ini menunjukkan potensi masalah INP jika pengguna berinteraksi selama frame animasi yang panjang ini.

Kode berikut mencatat semua entri LoAF dengan durasi pemblokiran lebih dari 100 milidetik saat interaksi terjadi selama frame. Angka 100 dipilih di sini karena kurang dari batas INP "baik" 200 milidetik untuk membantu mengidentifikasi potensi frame masalah, sekaligus menjaga jumlah frame animasi panjang yang dilaporkan seminimal mungkin. Anda dapat memilih nilai yang lebih tinggi atau lebih rendah bergantung pada kebutuhan Anda.

const REPORTING_THRESHOLD_MS = 100;

const observer = new PerformanceObserver(list => {
  for (const entry of list.getEntries()) {
    if (entry.blockingDuration > REPORTING_THRESHOLD_MS) {
      // Example here logs to console, but could also report back to analytics
      console.log(entry);
    }
  }
});
observer.observe({ type: 'long-animation-frame', buffered: true });

Mengamati frame animasi yang panjang selama update UI penting untuk meningkatkan kelancaran

Seperti yang disebutkan sebelumnya, melihat frame animasi panjang dengan durasi pemblokiran tinggi dapat membantu mengatasi responsivitas input. Namun, untuk kelancaran, Anda harus melihat semua frame animasi panjang dengan duration yang panjang.

Karena hal ini dapat menimbulkan banyak derau, sebaiknya Anda membatasi pengukuran ini ke titik-titik utama dengan pola seperti ini:

const REPORTING_THRESHOLD_MS = 100;

const observer = new PerformanceObserver(list => {
  if (measureImportantUIupdate) {
    for (const entry of list.getEntries()) {
      if (entry.duration > REPORTING_THRESHOLD_MS) {
        // Example here logs to console, but could also report back to analytics
        console.log(entry);
      }
    }
  }
});
observer.observe({ type: 'long-animation-frame', buffered: true });

async function doUIUpdatesWithMeasurements() {
  measureImportantUIupdate = true;
  await doUIUpdates();
  measureImportantUIupdate = false;
}

Mengamati frame animasi panjang terburuk

Daripada menetapkan nilai minimum, situs mungkin ingin mengumpulkan data pada frame animasi terpanjang, untuk mengurangi volume data yang perlu dikirim ke beacon. Jadi, berapa pun jumlah frame animasi panjang yang dialami halaman, hanya data untuk frame animasi terpanjang, lima, sepuluh, atau berapa pun jumlah frame animasi panjang yang benar-benar diperlukan yang akan dikirim kembali.

MAX_LOAFS_TO_CONSIDER = 10;
let longestBlockingLoAFs = [];

const observer = new PerformanceObserver(list => {
  longestBlockingLoAFs = longestBlockingLoAFs.concat(list.getEntries()).sort(
    (a, b) => b.blockingDuration - a.blockingDuration
  ).slice(0, MAX_LOAFS_TO_CONSIDER);
});
observer.observe({ type: 'long-animation-frame', buffered: true });

Strategi ini juga dapat digabungkan—hanya lihat 10 LoAF terburuk, dengan interaksi, yang lebih dari 100 milidetik.

Pada waktu yang tepat (idealnya pada peristiwa visibilitychange), beacon akan kembali ke Analytics. Untuk pengujian lokal, Anda dapat menggunakan console.table secara berkala:

console.table(longestBlockingLoAFs);

Mengidentifikasi pola umum dalam frame animasi yang panjang

Strategi alternatifnya adalah melihat skrip umum yang paling sering muncul dalam entri frame animasi yang panjang. Data dapat dilaporkan kembali di tingkat skrip dan posisi karakter untuk mengidentifikasi pelanggar berulang.

Hal ini mungkin sangat cocok untuk platform yang dapat disesuaikan, tempat tema atau plugin yang menyebabkan masalah performa dapat diidentifikasi di sejumlah situs.

Waktu eksekusi skrip umum—atau origin pihak ketiga—dalam frame animasi panjang dapat dijumlahkan dan dilaporkan kembali untuk mengidentifikasi kontributor umum pada frame animasi panjang di seluruh situs atau kumpulan situs. Misalnya, untuk melihat URL:

const observer = new PerformanceObserver(list => {
  const allScripts = list.getEntries().flatMap(entry => entry.scripts);
  const scriptSource = [...new Set(allScripts.map(script => script.sourceURL))];
  const scriptsBySource= scriptSource.map(sourceURL => ([sourceURL,
      allScripts.filter(script => script.sourceURL === sourceURL)
  ]));
  const processedScripts = scriptsBySource.map(([sourceURL, scripts]) => ({
    sourceURL,
    count: scripts.length,
    totalDuration: scripts.reduce((subtotal, script) => subtotal + script.duration, 0)
  }));
  processedScripts.sort((a, b) => b.totalDuration - a.totalDuration);
  // Example here logs to console, but could also report back to analytics
  console.table(processedScripts);
});

observer.observe({type: 'long-animation-frame', buffered: true});

Contoh output ini adalah:

(index) sourceURL count totalDuration
0 'https://example.consent.com/consent.js' 1 840
1 'https://example.com/js/analytics.js' 7 628
2 'https://example.chatapp.com/web-chat.js' 1 5

Menggunakan Long Animation Frames API dalam alat

API ini juga memungkinkan alat developer tambahan untuk proses debug lokal. Meskipun beberapa alat seperti Lighthouse dan Chrome DevTools telah dapat mengumpulkan sebagian besar data ini menggunakan detail pelacakan tingkat rendah, memiliki API tingkat tinggi ini dapat memungkinkan alat lain mengakses data ini.

Menampilkan data frame animasi panjang di DevTools

Anda dapat menampilkan frame animasi yang panjang di DevTools menggunakan performance.measure() API, yang kemudian ditampilkan di jalur waktu pengguna DevTools dalam rekaman aktivitas performa untuk menunjukkan tempat untuk memfokuskan upaya Anda guna meningkatkan performa. Dengan menggunakan DevTools Extensibility API, hal ini bahkan dapat ditampilkan di jalurnya sendiri:

const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    performance.measure('LoAF', {
      start: entry.startTime,
      end: entry.startTime + entry.duration,
      detail: {
        devtools: {
          dataType: "track-entry",
          track: "Long animation frames",
          trackGroup: "Performance Timeline",
          color: "tertiary-dark",
          tooltipText: 'LoAF'
        }
      }
    });
  }
});

observer.observe({ type: 'long-animation-frame', buffered: true });
Rekaman aktivitas Panel Performa DevTools dengan jalur kustom yang menampilkan data Frame Animasi Panjang yang dapat dibandingkan dengan diagram lingkaran api utama.
Menampilkan data frame Animasi yang panjang di DevTools.

Dalam jangka panjang, frame animasi yang panjang kemungkinan akan digabungkan ke dalam DevTools itu sendiri, tetapi cuplikan kode sebelumnya memungkinkannya ditampilkan di sana untuk sementara.

Entri pertama pada gambar sebelumnya juga menunjukkan tempat browser telah memproses beberapa tugas secara bersamaan dalam frame animasi panjang yang sama, bukan merender di antara tugas tersebut. Seperti yang disebutkan sebelumnya, hal ini dapat terjadi jika tidak ada tugas input prioritas tinggi, tetapi ada antrean tugas. Tugas panjang pertama memiliki beberapa pembaruan render yang harus diselesaikan (jika tidak, frame animasi panjang saat ini akan direset setelahnya, dan frame baru akan dimulai dengan tugas berikutnya), tetapi alih-alih langsung melakukan render tersebut, browser telah memproses sejumlah tugas tambahan dan baru kemudian melakukan tugas render panjang dan mengakhiri frame animasi panjang. Hal ini menunjukkan kegunaan melihat frame animasi yang panjang di DevTools, bukan hanya tugas yang panjang, untuk membantu mengidentifikasi render yang tertunda.

Menggunakan data frame animasi panjang di alat developer lainnya

Ekstensi Web Vitals telah menampilkan nilai dalam informasi debug ringkasan logging untuk mendiagnosis masalah performa.

Sekarang, data frame animasi panjang juga ditampilkan untuk setiap callback INP dan setiap interaksi:

Logging konsol Ekstensi Web Vitals.
Logging konsol Ekstensi Data Vital Web menampilkan data LoAF.

Menggunakan data frame animasi panjang di alat pengujian otomatis

Demikian pula, alat pengujian otomatis di pipeline CI/CD dapat menampilkan detail tentang potensi masalah performa dengan mengukur frame animasi yang panjang saat menjalankan berbagai rangkaian pengujian.

FAQ

Beberapa pertanyaan umum (FAQ) tentang API ini meliputi:

Mengapa tidak langsung memperluas atau melakukan iterasi pada Long Tasks API?

Ini adalah cara alternatif untuk melaporkan pengukuran potensi masalah responsivitas yang serupa, tetapi pada akhirnya berbeda. Penting untuk memastikan situs yang mengandalkan Long Tasks API yang ada terus berfungsi untuk menghindari gangguan pada kasus penggunaan yang ada.

Meskipun Long Tasks API dapat memanfaatkan beberapa fitur LoAF (seperti model atribusi yang lebih baik), kami yakin bahwa berfokus pada frame, bukan tugas, menawarkan banyak manfaat yang menjadikannya API yang secara fundamental berbeda dengan Long Tasks API yang ada.

Why do I not have script entries?

Hal ini dapat menunjukkan bahwa frame animasi yang lama bukan disebabkan oleh JavaScipt, tetapi karena pekerjaan render yang besar.

Hal ini juga dapat terjadi jika frame animasi yang lama adalah karena JavaScript, tetapi atribusi skrip tidak dapat diberikan karena berbagai alasan privasi seperti yang disebutkan sebelumnya (terutama karena JavaScript tidak dimiliki oleh halaman).

Mengapa saya memiliki entri skrip, tetapi tidak ada, atau hanya memiliki informasi sumber yang terbatas?

Hal ini dapat terjadi karena beberapa alasan, termasuk tidak ada sumber yang baik untuk dituju.

Informasi skrip juga akan dibatasi hanya untuk sourceURL (tidak termasuk pengalihan apa pun) untuk skrip no-cors cross-origin, dengan string kosong untuk sourceFunctionName dan -1 untuk sourceCharPosition. Masalah ini dapat diatasi dengan mengambil skrip tersebut menggunakan CORS dengan menambahkan crossOrigin = "anonymous" ke panggilan <script>.

Misalnya, skrip Google Tag Manager default yang akan ditambahkan ke halaman:

<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXX');</script>
<!-- End Google Tag Manager -->

Dapat ditingkatkan untuk menambahkan j.crossOrigin = "anonymous" agar detail atribusi lengkap dapat diberikan untuk GTM.

Apakah ini akan menggantikan Long Tasks API?

Meskipun kami yakin Long Animation Frames API adalah API yang lebih baik dan lebih lengkap untuk mengukur tugas yang lama, saat ini, tidak ada rencana untuk menghentikan penggunaan Long Tasks API.

Masukan yang diinginkan

Masukan dapat diberikan di daftar Masalah GitHub, atau bug dalam implementasi API Chrome dapat dilaporkan di issue tracker Chrome.

Kesimpulan

Long Animation Frames API adalah API baru yang menarik dengan banyak potensi keunggulan dibandingkan Long Tasks API sebelumnya.

INP terbukti menjadi alat utama untuk mengatasi masalah responsivitas seperti yang diukur oleh INP. INP adalah metrik yang sulit dioptimalkan dan API ini adalah salah satu cara yang dicoba oleh tim Chrome untuk memudahkan developer mengidentifikasi dan mengatasi masalah.

Namun, cakupan Long Animation Frames API tidak hanya mencakup INP, dan dapat membantu mengidentifikasi penyebab lain dari update lambat yang dapat memengaruhi kelancaran pengalaman pengguna situs secara keseluruhan.

Ucapan terima kasih

Gambar thumbnail oleh Henry Be di Unsplash.