Pelanggaran Tugas JavaScript yang berjalan lama membutuhkan xx ms

331

Baru-baru ini, saya mendapat peringatan semacam ini, dan ini adalah pertama kalinya saya mendapatkannya:

[Violation] Long running JavaScript task took 234ms
[Violation] Forced reflow while executing JavaScript took 45ms

Saya sedang mengerjakan proyek grup dan saya tidak tahu dari mana ini berasal. Ini tidak pernah terjadi sebelumnya. Tiba-tiba, itu muncul ketika orang lain terlibat dalam proyek. Bagaimana cara menemukan file / fungsi apa yang menyebabkan peringatan ini? Saya sudah mencari jawabannya, tetapi sebagian besar tentang solusi tentang bagaimana menyelesaikannya. Saya tidak dapat menyelesaikannya jika saya tidak dapat menemukan sumber masalahnya.

Dalam hal ini, peringatan hanya muncul di Chrome. Saya mencoba menggunakan Edge, tetapi saya tidak mendapatkan peringatan serupa, dan saya belum mengujinya di Firefox.

Saya bahkan mendapatkan kesalahan dari jquery.min.js:

[Violation] Handler took 231ms of runtime (50ms allowed)            jquery.min.js:2
Procatmer
sumber
Di mana Anda melihat peringatan ini? Anda tidak mengatakan di lingkungan mana Anda bekerja. Dengan asumsi beberapa browser, tetapi yang mana dll?
Sami Kuhmonen
3
@SamiKuhmonen maaf untuk itu, saya sudah memperbarui pertanyaan saya. saya menggunakan Chrome. saya tidak menemukan kesalahan serupa di Edge.
Procatmer
8
Saya hanya ingin menambahkan bahwa pesan peringatan ini, diperkenalkan akhir 2016, juga dapat muncul karena ekstensi apa pun yang mungkin Anda pasang di Chrome. Sangat mudah untuk memeriksa dengan menguji dalam mode pribadi.
Fer
1
Mengklik tautan sebelah kanan, yang menunjukkan pada Anda skrip di mana pelanggaran terjadi, akan membawa Anda ke tempat di kode di mana itu terjadi.
bluehipy
Saya menggunakan Ionic 4 (Angular 8), kode saya berfungsi dengan baik, tiba-tiba pelanggaran seperti ini mulai terjadi - tidak ada data yang ditampilkan dalam daftar saya sekarang?
Kapil Raghuwanshi

Jawaban:

278

Pembaruan : Chrome 58+ menyembunyikan pesan debug ini dan lainnya secara default. Untuk menampilkannya, klik panah di sebelah 'Info' dan pilih 'Verbose'.

Chrome 57 mengaktifkan 'sembunyikan pelanggaran' secara default. Untuk mengaktifkannya kembali, Anda perlu mengaktifkan filter dan hapus centang pada kotak 'sembunyikan pelanggaran'.

tiba-tiba muncul ketika orang lain terlibat dalam proyek

Saya pikir kemungkinan besar Anda memperbarui ke Chrome 56. Peringatan ini adalah fitur baru yang luar biasa, menurut saya, harap matikan saja jika Anda putus asa dan penilai Anda akan mengambil nilai dari Anda. Masalah yang mendasarinya ada di browser lain tetapi browser tidak memberitahu Anda ada masalah. Tiket Chromium ada di sini tetapi sebenarnya tidak ada diskusi yang menarik tentangnya.

Pesan-pesan ini adalah peringatan bukan kesalahan karena itu tidak benar-benar akan menyebabkan masalah besar. Ini dapat menyebabkan frame terjatuh atau menyebabkan pengalaman yang kurang mulus.

Mereka layak diselidiki dan diperbaiki untuk meningkatkan kualitas aplikasi Anda. Cara untuk melakukan ini adalah dengan memperhatikan keadaan pesan apa yang muncul, dan melakukan pengujian kinerja untuk mempersempit di mana masalah terjadi. Cara paling sederhana untuk memulai pengujian kinerja adalah dengan memasukkan beberapa kode seperti ini:

function someMethodIThinkMightBeSlow() {
    const startTime = performance.now();

    // Do the normal stuff for this function

    const duration = performance.now() - startTime;
    console.log(`someMethodIThinkMightBeSlow took ${duration}ms`);
}

Jika Anda ingin menjadi lebih maju, Anda juga bisa menggunakan profiler Chrome , atau menggunakan perpustakaan benchmark seperti ini .

Setelah Anda menemukan beberapa kode yang membutuhkan waktu lama (50ms adalah ambang Chrome), Anda memiliki beberapa opsi:

  1. Hentikan sebagian / semua tugas itu yang mungkin tidak perlu
  2. Cari tahu bagaimana melakukan tugas yang sama lebih cepat
  3. Bagilah kode menjadi beberapa langkah asinkron

(1) dan (2) mungkin sulit atau tidak mungkin, tetapi kadang-kadang sangat mudah dan harus menjadi upaya pertama Anda. Jika perlu, itu harus selalu memungkinkan untuk dilakukan (3). Untuk melakukan ini, Anda akan menggunakan sesuatu seperti:

setTimeout(functionToRunVerySoonButNotNow);

atau

// This one is not available natively in IE, but there are polyfills available.
Promise.resolve().then(functionToRunVerySoonButNotNow);

Anda dapat membaca lebih lanjut tentang sifat asinkron dari JavaScript di sini .

voltrevo
sumber
16
Hanya sebuah saran, alih-alih menggunakan performance.now(), Anda dapat menggunakan console.time( developer.mozilla.org/en-US/docs/Web/API/Console/time ) console.time('UniquetLabelName') ....code here.... console.timeEnd('UniqueLabelName')
denislexic
@dlexlexic kurasa begitu. Saya tidak yakin apa nilai yang benar-benar menambah. Saya berpendapat bahwa belajar tentang operasi yang mendasari mendapatkan waktu saat ini dan membangun yang lebih berharga.
voltrevo
34
Jawaban yang bagus, voltrevo! Pertanyaan saya adalah, jika kode seperti ini merupakan pelanggaran, sebenarnya apa yang dilanggar? Harus ada semacam standar yang diterapkan Google, tetapi apakah standar itu didokumentasikan secara publik di mana saja?
Bungler
1
@Bungler Entahlah, saya ingin tahu apakah ada pedoman yang merujuknya juga.
voltrevo
4
@ Bungler Saya hanya bisa menebak bahwa itu mengatakan bahwa kode yang menjiwai melanggar memberikan setidaknya 60 frame per detik dan karena itu memberikan pengalaman pengguna yang buruk. .
user895400
90

Ini hanya peringatan seperti yang disebutkan semua orang. Namun, jika Anda ingin menyelesaikan ini (yang seharusnya), maka Anda perlu mengidentifikasi apa yang menyebabkan peringatan itu terlebih dahulu. Tidak ada satu alasan karena itu Anda bisa mendapatkan peringatan reflow paksa. Seseorang telah membuat daftar untuk beberapa opsi yang memungkinkan. Anda dapat mengikuti diskusi untuk informasi lebih lanjut.
Inilah inti dari kemungkinan alasannya:

Apa yang memaksa tata letak / reflow

Semua properti atau metode di bawah ini, ketika diminta / dipanggil dalam JavaScript, akan memicu browser untuk secara sinkron menghitung gaya dan tata letak *. Ini juga disebut reflow atau tata letak meronta-ronta , dan merupakan hambatan kinerja umum.

Elemen

Metrik kotak
  • elem.offsetLeft, elem.offsetTop, elem.offsetWidth, elem.offsetHeight,elem.offsetParent
  • elem.clientLeft, elem.clientTop, elem.clientWidth,elem.clientHeight
  • elem.getClientRects(), elem.getBoundingClientRect()
Gulir barang
  • elem.scrollBy(), elem.scrollTo()
  • elem.scrollIntoView(), elem.scrollIntoViewIfNeeded()
  • elem.scrollWidth, elem.scrollHeight
  • elem.scrollLeft, elem.scrollTopjuga, mengaturnya
Fokus
  • elem.focus() dapat memicu tata letak paksa ganda ( sumber )
Juga…
  • elem.computedRole, elem.computedName
  • elem.innerText( sumber )

getComputedStyle

window.getComputedStyle()biasanya akan memaksa gaya recalc ( sumber )

window.getComputedStyle() akan memaksa tata letak, juga, jika salah satu dari yang berikut ini benar:

  1. Unsurnya ada di pohon bayangan
  2. Ada pertanyaan media (yang terkait dengan viewport). Secara khusus, salah satu dari berikut ini: ( sumber ) * min-width, min-height, max-width, max-height, width, height * aspect-ratio, min-aspect-ratio,max-aspect-ratio
    • device-pixel-ratio, resolution,orientation
  3. Properti yang diminta adalah salah satu dari yang berikut: ( sumber )
    • height, width * top, right, bottom, left * margin[ -top, -right, -bottom, -left, Atau singkatan ] hanya jika margin adalah tetap. * padding[ -top, -right, -bottom, -left, Atau singkatan ] hanya jika padding adalah tetap. * transform, transform-origin, perspective-origin * translate, rotate, scale * webkit-filter, backdrop-filter * motion-path, motion-offset, motion-rotation * x, y, rx,ry

jendela

  • window.scrollX, window.scrollY
  • window.innerHeight, window.innerWidth
  • window.getMatchedCSSRules() hanya gaya gaya

Formulir

  • inputElem.focus()
  • inputElem.select(), textareaElem.select()( sumber )

Peristiwa mouse

  • mouseEvt.layerX, mouseEvt.layerY, mouseEvt.offsetX, mouseEvt.offsetY ( Sumber )

dokumen

  • doc.scrollingElement hanya gaya gaya

Jarak

  • range.getClientRects(), range.getBoundingClientRect()

SVG

dapat diedit

  • Banyak & banyak hal, ... termasuk menyalin gambar ke clipboard ( sumber )

Lihat lebih lanjut di sini .

Juga, inilah kode sumber Chromium dari masalah asli dan diskusi tentang API kinerja untuk peringatan.


Sunting: Ada juga artikel tentang cara meminimalkan tata letak reflow pada PageSpeed ​​Insight oleh Google . Ini menjelaskan apa itu browser reflow:

Reflow adalah nama proses peramban web untuk menghitung ulang posisi dan geometri elemen dalam dokumen, untuk tujuan rendering ulang sebagian atau seluruh dokumen. Karena reflow adalah operasi pemblokiran pengguna di peramban, maka berguna bagi pengembang untuk memahami cara meningkatkan waktu reflow dan juga untuk memahami efek dari berbagai properti dokumen (kedalaman DOM, efisiensi aturan CSS, berbagai jenis perubahan gaya) pada reflow waktu. Kadang-kadang merefleksikan satu elemen dalam dokumen mungkin perlu merefleksikan elemen induknya dan juga elemen yang mengikutinya.

Selain itu, ini menjelaskan cara menguranginya:

  1. Kurangi kedalaman DOM yang tidak perlu. Perubahan pada satu tingkat di pohon DOM dapat menyebabkan perubahan di setiap tingkat pohon - semua jalan sampai ke root, dan semua jalan turun ke anak-anak dari simpul yang dimodifikasi. Hal ini menyebabkan lebih banyak waktu dihabiskan untuk melakukan reflow.
  2. Minimalkan aturan CSS, dan hapus aturan CSS yang tidak digunakan.
  3. Jika Anda membuat perubahan render yang rumit seperti animasi, lakukan itu di luar alur. Gunakan posisi-absolut atau posisi-tetap untuk mencapai ini.
  4. Hindari selektor CSS kompleks yang tidak perlu - selektor keturunan khususnya - yang membutuhkan lebih banyak daya CPU untuk melakukan pencocokan pemilih.
cupu
sumber
1
Latar belakang lainnya: kode sumber Chromium dari masalah asli dan diskusi tentang API kinerja untuk peringatan.
robocat
1
Menurut hal di atas, cukup membaca element.scrollTop memicu reflow. Ini mengejutkan saya sebagai fenomena kontra-intuitif. Saya bisa mengerti mengapa pengaturan element.scrollTop akan memicu reflow, tetapi hanya membaca nilainya? Adakah yang bisa menjelaskan lebih lanjut mengapa ini terjadi, jika memang demikian?
David Edwards
29

Beberapa ide:

  • Hapus setengah dari kode Anda (mungkin melalui komentar).

    • Apakah masalahnya masih ada? Bagus, Anda sudah mempersempit kemungkinan! Ulang.

    • Apakah masalahnya tidak ada? Ok, lihat bagian yang Anda komentari!

  • Apakah Anda menggunakan sistem kontrol versi (misalnya, Git)? Jika demikian, git checkoutbeberapa dari komitmen Anda yang terbaru. Kapan masalah tersebut muncul? Lihatlah komit untuk melihat kode apa yang berubah saat masalah pertama kali tiba.

therobinkim
sumber
Terima kasih atas jawaban Anda. saya memang menghapus setengah dan bahkan mengecualikan file .js utama saya dari proyek. entah bagaimana kesalahan masih terjadi. ini sebabnya saya sangat frustasi tentang itu. dan ya, saya menggunakan git. saya baru menyadari kesalahan ini hari ini. sudah ada banyak komitmen sejak ini menjadi proyek kelompok. mungkin melakukan pemeriksaan mendalam. terima kasih lagi untuk ide-idenya.
Procatmer
@procatmer menggunakan strategi yang sama dengan menemukan git commit. Misalnya, jika saya memiliki 10 komitmen (A, B, C, D, E, F, G, H, I, J) di mana A adalah yang tertua, saya akan git checkout Emelihat apakah masalahnya sudah ada. Jika ya, saya akan terus mencari masalah di paruh pertama komitmen. Kalau tidak, saya mencari masalah di babak kedua.
therobinkim
1
@procatmer Juga, jika Anda menghapus .jsfile utama Anda dan masalahnya tetap ada ... itu bisa jadi perpustakaan yang Anda bawa melalui <script src="...">tag! Mungkin sesuatu yang tidak perlu dikhawatirkan (terutama karena itu hanya peringatan)?
therobinkim
1
Saya akhirnya menemukan di mana masalahnya. saya menggunakan ide kedua Anda untuk melacak perubahan. dan ya, masalahnya berasal dari .jsfile eksternal . rupanya, itu penting. itu memperlambat situs saya cukup signifikan. Bagaimanapun, terima kasih lagi atas jawaban dan ide Anda.
procatmer
2
Anda dapat menggunakan git bisect untuk menerapkan pencarian biner. Saya pikir itu hanya untuk tujuan menemukan bug.
pietrovismara
12

Untuk mengidentifikasi sumber masalah, jalankan aplikasi Anda, dan catat di tab Kinerja Chrome .

Di sana Anda dapat memeriksa berbagai fungsi yang membutuhkan waktu lama untuk dijalankan. Dalam kasus saya, yang berkorelasi dengan peringatan di konsol berasal dari file yang dimuat oleh ekstensi AdBlock, tetapi ini bisa menjadi hal lain dalam kasus Anda.

Periksa file-file ini dan cobalah untuk mengidentifikasi apakah ini kode ekstensi atau milik Anda. (Jika itu milik Anda, maka Anda telah menemukan sumber masalah Anda.)

Matt Leonowicz
sumber
Tidak, saya tidak punya AdBlock dan saya masih mendapatkannya di konsol.
Nikola Stojaković
Cobalah untuk menganalisanya dengan tab Performance, dan cari sumber fungsi yang berjalan lama. Ini bisa apa saja, tetapi ini merupakan cara potensial untuk mengidentifikasi sumber masalah.
Matt Leonowicz
6

Lihat di konsol Chrome di bawah tab Network dan temukan skrip yang membutuhkan waktu paling lama untuk dimuat.

Dalam kasus saya ada satu set Angular add on scripts yang telah saya sertakan tetapi belum digunakan dalam aplikasi:

<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.8/angular-ui-router.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-utils/0.1.1/angular-ui-utils.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular-animate.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular-aria.min.js"></script>

Ini adalah satu-satunya file JavaScript yang membutuhkan waktu lebih lama untuk memuat daripada waktu yang ditentukan oleh "Tugas Berlari Panjang".

Semua file ini berjalan di situs web saya yang lain tanpa kesalahan yang dihasilkan tetapi saya mendapatkan kesalahan "Tugas Berlari Panjang" ini pada aplikasi web baru yang hampir tidak memiliki fungsi apa pun. Kesalahan berhenti segera setelah dihapus.

Dugaan terbaik saya adalah bahwa add-ons Angular ini mencari secara rekursif ke bagian DOM yang semakin dalam untuk tag awal mereka - tanpa menemukan, mereka harus melintasi seluruh DOM sebelum keluar, yang membutuhkan waktu lebih lama daripada yang diharapkan Chrome - dengan demikian peringatan.

Jordan Reddick
sumber
6

Saya menemukan akar pesan ini dalam kode saya, yang mencari dan menyembunyikan atau menunjukkan node (offline). Ini adalah kode saya:

search.addEventListener('keyup', function() {
    for (const node of nodes)
        if (node.innerText.toLowerCase().includes(this.value.toLowerCase()))
            node.classList.remove('hidden');
        else
            node.classList.add('hidden');
});

Tab kinerja (profiler) menunjukkan acara yang memakan waktu sekitar 60 ms: Reflow perhitungan ulang tata letak profiler kinerja Chromium

Sekarang:

search.addEventListener('keyup', function() {
    const nodesToHide = [];
    const nodesToShow = [];
    for (const node of nodes)
        if (node.innerText.toLowerCase().includes(this.value.toLowerCase()))
            nodesToShow.push(node);
        else
            nodesToHide.push(node);

    nodesToHide.forEach(node => node.classList.add('hidden'));
    nodesToShow.forEach(node => node.classList.remove('hidden'));
});

Tab kinerja (profiler) sekarang menunjukkan acara yang memakan waktu sekitar 1 ms: Profiler Chromium gelap

Dan saya merasa bahwa pencarian bekerja lebih cepat sekarang (229 node).

Vitaly Zdanevich
sumber
3
Singkatnya, dengan menerima pelanggaran, Anda dapat mengoptimalkan kode Anda, dan kinerjanya lebih baik sekarang.
Pengguna yang bukan pengguna
3

Saya menemukan solusi dalam kode sumber Apache Cordova. Mereka menerapkan seperti ini:

var resolvedPromise = typeof Promise == 'undefined' ? null : Promise.resolve();
var nextTick = resolvedPromise ? function(fn) { resolvedPromise.then(fn); } : function(fn) { setTimeout(fn); };

Implementasi sederhana, tetapi cara cerdas.

Di Android 4.4, gunakan Promise. Untuk browser yang lebih lama, gunakansetTimeout()


Pemakaian:

nextTick(function() {
  // your code
});

Setelah memasukkan kode trik ini, semua pesan peringatan hilang.

wf9a5m75
sumber
2

Jika Anda menggunakan Chrome Canary (atau Beta), cukup centang opsi 'Sembunyikan Pelanggaran'.

Sembunyikan Kotak centang Pelanggaran di Chrome 56 Console

zhaoming
sumber
1

Ini adalah kesalahan pelanggaran dari Google Chrome yang menunjukkan kapan Verbose level logging diaktifkan.

Contoh pesan kesalahan:

tangkapan layar peringatan

Penjelasan:

Reflow adalah nama proses peramban web untuk menghitung ulang posisi dan geometri elemen dalam dokumen, untuk tujuan rendering ulang sebagian atau seluruh dokumen. Karena reflow adalah operasi pemblokiran pengguna di peramban, maka berguna bagi pengembang untuk memahami cara meningkatkan waktu reflow dan juga untuk memahami efek dari berbagai properti dokumen (kedalaman DOM, efisiensi aturan CSS, berbagai jenis perubahan gaya) pada reflow waktu. Kadang-kadang merefleksikan satu elemen dalam dokumen mungkin perlu merefleksikan elemen induknya dan juga elemen yang mengikutinya.

Artikel asli: Meminimalkan reflow browser oleh Lindsey Simon, Pengembang UX, yang diposting di developers.google.com.

Dan ini adalah tautan yang diberikan Google Chrome pada Anda di profiler Kinerja, pada profil tata letak (wilayah ungu muda), untuk info lebih lanjut tentang peringatan tersebut.

Paul-Sebastian Manole
sumber
0

Menambahkan wawasan saya di sini sebagai utas ini adalah pertanyaan "pergi ke" stackoverflow pada topik.

Masalah saya ada di aplikasi Material-UI (tahap awal)

  • penempatan penyedia Tema kustom adalah penyebabnya

ketika saya melakukan beberapa perhitungan yang memaksa rendering halaman (satu komponen, "tampilkan hasil", tergantung pada apa yang diatur dalam yang lain, "masukan bagian").

Semuanya baik-baik saja sampai saya memperbarui "keadaan" yang memaksa "komponen hasil" untuk dirubah. Masalah utama di sini adalah bahwa saya memiliki tema material-ui ( https://material-ui.com/customization/theming/#a-note-on-performance ) di renderer yang sama (App.js / return ..) sebagai "komponen hasil", SummaryAppBarPure

Solusi adalah mengangkat ThemeProvider satu tingkat ke atas (Index.js), dan membungkus komponen Aplikasi di sini, sehingga tidak memaksa ThemeProvider untuk menghitung ulang dan menggambar / tata letak / reflow.

sebelum

di App.js:

  return (
    <>
      <MyThemeProvider>
      <Container className={classes.appMaxWidth}>

        <SummaryAppBarPure
//...

di index.js

ReactDOM.render(
  <React.StrictMode>
      <App />
//...

setelah

di App.js:

return (
    <>
      {/* move theme to index. made reflow problem go away */}
      {/* <MyThemeProvider> */}
      <Container className={classes.appMaxWidth}>

        <SummaryAppBarPure
//...

di index.js

ReactDOM.render(
  <React.StrictMode>
    <MyThemeProvider>
      <App />
//...
JimiSweden
sumber
-2

Reflow paksa sering terjadi ketika Anda memiliki fungsi yang dipanggil beberapa kali sebelum akhir eksekusi.

Misalnya, Anda mungkin memiliki masalah pada ponsel cerdas, tetapi tidak pada peramban klasik.

Saya sarankan menggunakan setTimeoutuntuk menyelesaikan masalah.

Ini tidak terlalu penting, tetapi saya ulangi, masalah muncul ketika Anda memanggil suatu fungsi beberapa kali, dan bukan ketika fungsi tersebut membutuhkan lebih dari 50 ms. Saya pikir Anda salah dalam jawaban Anda.

  1. Matikan panggilan 1-per-1 dan muat ulang kode untuk melihat apakah masih menghasilkan kesalahan.
  2. Jika skrip kedua menyebabkan kesalahan, gunakan setTimeOutberdasarkan pada durasi pelanggaran.
Cherif
sumber
Ini bukan solusi. Itu saran yang lebih baik dibiarkan sebagai komentar untuk pertanyaan asli.
Paul-Sebastian Manole
-6

Ini bukan kesalahan hanya pesan sederhana. Untuk mengeksekusi perubahan pesan ini
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">(contoh)
menjadi
<!DOCTYPE html>(sumber Firefox mengharapkan ini)

Pesan ditampilkan di Google Chrome 74 dan Opera 60. Setelah mengubahnya jelas, 0 verbose.
Pendekatan solusi

Gerdixx
sumber
5
Hanya beberapa saran: Jawaban Anda tidak ada hubungannya dengan pertanyaan. Perbaiki jawaban Anda atau hapus. Pertanyaannya adalah "mengapa konsol browser Chrome menunjukkan peringatan pelanggaran". Jawabannya adalah itu adalah fitur di browser Chrome yang lebih baru di mana ia memberi tahu Anda jika halaman web menyebabkan reflows browser yang berlebihan saat menjalankan JS. Silakan merujuk sumber ini dari Google untuk info lebih lanjut.
Paul-Sebastian Manole