İhlal Uzun süren JavaScript görevi xx ms sürdü


330

Son zamanlarda, bu tür bir uyarı aldım ve bu benim ilk defa alıyorum:

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

Bir grup projesi üzerinde çalışıyorum ve bunun nereden geldiği hakkında hiçbir fikrim yok. Bu daha önce hiç olmamıştı. Aniden, başka biri projeye dahil olduğunda ortaya çıktı. Bu uyarıya hangi dosya / işlevin neden olduğunu nasıl bulabilirim? Cevabı arıyordum, ancak çoğunlukla bunun nasıl çözüleceğine dair çözüm hakkında. Sorunun kaynağını bile bulamıyorsam çözemiyorum.

Bu durumda uyarı yalnızca Chrome'da görünür. Edge'i kullanmaya çalıştım, ancak benzer uyarılar almadım ve henüz Firefox'ta test etmedim.

Hatta hata alıyorum jquery.min.js:

[Violation] Handler took 231ms of runtime (50ms allowed)            jquery.min.js:2

Bu uyarıyı nerede görüyorsunuz? Hangi ortamda çalıştığınızı söylemiyorsunuz. Bazı tarayıcılar varsayarsak hangileri vb.?
Sami Kuhmonen

3
@SamiKuhmonen bunun için üzgünüm, sorumu güncelledim. Chrome kullandım. Edge'de benzer bir hata bulamadım.
procatmer

8
Sadece 2016'nın sonlarında tanıtılan bu uyarı mesajının Chrome'a ​​yüklemiş olabileceğiniz uzantılar nedeniyle de görünebileceğini eklemek istedim. Özel modda test ederek bunu kontrol etmek kolaydır.
Fer

1
Sağ taraftaki bağlantıyı tıkladığınızda, ihlallerin gerçekleştiği komut dosyasını size bildirir, kodun gerçekleştiği yere götürür.
bluehipy

Ionic 4 (Açısal 8) kullanıyorum, kodum iyi çalışıyordu, aniden bu tür bir ihlal gelmeye başladı - şimdi listemde gösterilen veri yok mu?
Kapil Raghuwanshi

Yanıtlar:


278

Güncelleme : Chrome 58+ bu ve diğer hata ayıklama iletilerini varsayılan olarak gizledi. Bunları görüntülemek için 'Bilgi'nin yanındaki oku tıklayın ve' Ayrıntılı 'seçeneğini belirtin.

Chrome 57 varsayılan olarak 'ihlalleri gizle' seçeneğini açtı. Bunları tekrar açmak için filtreleri etkinleştirmeniz ve 'ihlalleri gizle' kutusunun işaretini kaldırmanız gerekir.

aniden projeye başka birisi katıldığında ortaya çıkıyor

Sanırım Chrome 56'ya güncelleme yapma olasılığınız daha yüksek. Bu uyarı harika bir yeni özellik, bence, lütfen sadece umutsuzsanız ve değerlendiriciniz sizden not alacaksa kapatın. Temel problemler diğer tarayıcılarda var, ancak tarayıcılar size bir sorun olduğunu söylemiyor. Chromium bileti burada ancak bununla ilgili ilginç bir tartışma yok.

Bu mesajlar hatalar yerine uyarılardır çünkü gerçekten büyük sorunlara neden olmaz. Çerçevelerin düşmesine veya başka şekilde daha az düzgün bir deneyime neden olabilir.

Ancak, uygulamanızın kalitesini artırmak için araştırmaya ve düzeltmeye değer. Bunu yapmanın yolu, mesajların hangi koşullara göründüğüne dikkat etmek ve sorunun oluştuğu yeri daraltmak için performans testi yapmaktır. Performans testine başlamanın en basit yolu, aşağıdaki gibi bir kod eklemektir:

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

    // Do the normal stuff for this function

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

Daha gelişmiş almak istiyorsanız, ayrıca kullanabilirsiniz Chrome'un profilcisini veya benzeri bir kıyaslama kütüphaneden yararlanabilirler bu bir .

Uzun süren bir kod bulduğunuzda (50ms, Chrome'un eşiğidir), birkaç seçeneğiniz vardır:

  1. Gereksiz olabilecek bu görevin bir kısmını / tümünü kesin
  2. Aynı görevi daha hızlı nasıl yapacağınızı öğrenin
  3. Kodu birden fazla eşzamansız adıma bölme

(1) ve (2) zor veya imkansız olabilir, ancak bazen gerçekten kolaydır ve ilk denemeniz olmalıdır. Gerekirse, her zaman mümkün olmalıdır (3). Bunu yapmak için şöyle bir şey kullanacaksınız:

setTimeout(functionToRunVerySoonButNotNow);

veya

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

JavaScript'in eşzamansız yapısı hakkında daha fazla bilgiyi buradan edinebilirsiniz .


16
Sadece bir öneri, kullanmak yerine, performance.now()kullanabilirsiniz console.time( developer.mozilla.org/en-US/docs/Web/API/Console/time ) console.time('UniquetLabelName') ....code here.... console.timeEnd('UniqueLabelName')
denislexic

@ denislexic Sanırım. Gerçekten hangi değeri eklediğinden emin değilim. Şimdiki zamanı elde etmenin ve bunun üzerine inşa etmenin altında yatan operasyon hakkında öğrenmenin daha değerli olduğunu iddia ediyorum.
voltrevo

34
Harika cevap, voltrevo! Sorum şu, eğer böyle bir kod bu bir ihlal ise, tam olarak neyi ihlal ediyor? Google'ın uyguladığı bir tür standart olmalı, ancak bu standart her yerde herkese açık olarak belgelenmiş mi?
2017'de Bungler

1
@Bungler Dunno, bahsettiği bazı yönergeler olup olmadığını bilmek istiyorum.
voltrevo

4
@Bungler Sadece canlandırılan kodun saniyede en az 60 kare sağlamayı ve dolayısıyla kötü bir kullanıcı deneyimi sunmayı ihlal ettiğini söyleyebilirim. .
user895400

90

Bunlar sadece herkesin belirttiği gibi uyarılardır. Ancak, bunları çözmeye hevesliyseniz (ki yapmanız gerekir), önce uyarıya neyin neden olduğunu belirlemeniz gerekir. Kuvvet yeniden akıtma uyarısı almanızın tek bir nedeni yoktur. Birisi bazı olası seçenekler için bir liste oluşturdu . Daha fazla bilgi için tartışmayı takip edebilirsiniz.
İşte olası nedenlerin özeti:

Düzeni / yeniden akıtmayı zorlayan nedir

JavaScript'te istendiğinde / çağrıldığında aşağıdaki özelliklerin veya yöntemlerin tümü, tarayıcıyı stili ve düzeni * senkronize olarak hesaplaması için tetikler. Buna yeniden akış veya düzen atma da denir ve genel performans darboğazıdır.

eleman

Kutu metrikleri
  • elem.offsetLeft, elem.offsetTop, elem.offsetWidth, elem.offsetHeight,elem.offsetParent
  • elem.clientLeft, elem.clientTop, elem.clientWidth,elem.clientHeight
  • elem.getClientRects(), elem.getBoundingClientRect()
Öğeleri kaydır
  • elem.scrollBy(), elem.scrollTo()
  • elem.scrollIntoView(), elem.scrollIntoViewIfNeeded()
  • elem.scrollWidth, elem.scrollHeight
  • elem.scrollLeft, elem.scrollTopayrıca, onları ayarlama
odak
  • elem.focus()çift zorunlu düzeni tetikleyebilir ( kaynak )
Ayrıca…
  • elem.computedRole, elem.computedName
  • elem.innerText( kaynak )

getComputedStyle

window.getComputedStyle()genellikle stil yeniden hesaplamasını zorlar ( kaynak )

window.getComputedStyle() aşağıdakilerden herhangi biri doğruysa düzeni de zorlar:

  1. Öğe gölge ağacında
  2. Medya sorguları var (görüntü alanı ile ilgili olanlar). Özellikle, aşağıdakilerden biri: ( kaynak ) * min-width, min-height, max-width, max-height, width, height * aspect-ratio, min-aspect-ratio,max-aspect-ratio
    • device-pixel-ratio, resolution,orientation
  3. İstenen mülk aşağıdakilerden biri: ( kaynak )
    • height, width * top, right, bottom, left * margin[ -top, -right, -bottom, -left, Ya da kısaltılmış ] marjı sabitlenir sadece. * padding[ -top, -right, -bottom, -left, Ya da kısaltılmış ] dolgu sabitlenir sadece. * transform, transform-origin, perspective-origin * translate, rotate, scale * webkit-filter, backdrop-filter * motion-path, motion-offset, motion-rotation * x, y, rx,ry

pencere

  • window.scrollX, window.scrollY
  • window.innerHeight, window.innerWidth
  • window.getMatchedCSSRules() sadece tarzı zorlar

Formlar

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

Fare olayları

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

belge

  • doc.scrollingElement sadece tarzı zorlar

Aralık

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

SVG

contenteditable

  • Çok sayıda şey,… bir görüntüyü panoya kopyalamak da dahil ( kaynak )

Buradan daha fazlasını kontrol edin .

Ayrıca, burada Krom kaynak kodundan İşte orijinal konuya ve performans API hakkında tartışma uyarıları.


Düzenleme: Google tarafından PageSpeed ​​Insight'ta düzen yeniden akışının en aza indirilmesine ilişkin bir makale de vardır . Tarayıcı yeniden akışının ne olduğunu açıklar:

Yeniden akış, belgenin bir kısmını veya tamamını yeniden oluşturmak amacıyla belgedeki öğelerin konumlarını ve geometrilerini yeniden hesaplamaya yönelik web tarayıcısı işleminin adıdır. Yeniden akış tarayıcıda bir kullanıcı engelleme işlemi olduğundan, geliştiricilerin yeniden akış süresinin nasıl iyileştirileceğini ve çeşitli belge özelliklerinin (DOM derinliği, CSS kural verimliliği, farklı stil değişiklikleri türleri) yeniden akış üzerindeki etkilerini anlamaları yararlıdır zaman. Bazen belgedeki tek bir öğenin yeniden düzenlenmesi, üst öğelerinin ve onu izleyen öğelerin yeniden düzenlenmesini gerektirebilir.

Ayrıca, nasıl en aza indirileceğini açıklar:

  1. Gereksiz DOM derinliğini azaltın. DOM ağacındaki bir düzeydeki değişiklikler, ağacın her düzeyinde köklere kadar ve değiştirilen düğümün alt öğelerine kadar değişikliklere neden olabilir. Bu, yeniden düzenleme için daha fazla zaman harcanmasına neden olur.
  2. CSS kurallarını en aza indirin ve kullanılmayan CSS kurallarını kaldırın.
  3. Animasyonlar gibi karmaşık oluşturma değişiklikleri yaparsanız, bunu akıştan çıkarın. Bunu yapmak için mutlak veya sabit konum kullanın.
  4. Seçici eşleştirmesi yapmak için daha fazla CPU gücü gerektiren gereksiz karmaşık CSS seçicilerinden - özellikle de alt seçicilerden - kaçının.

1
Daha fazla arka plan: den Krom kaynak kodu orijinal konuya ve performans API hakkında tartışma uyarıları.
robocat

1
Yukarıdakilere göre, element.scrollTop öğesinin yeniden okunması tetiklenir. Bu bana karşı sezgisel bir fenomen olarak dikkat çekiyor. Ayar element.scrollTop neden bir yeniden akış tetikleyeceğini, ancak sadece değerini okuduğunu anlayabiliyorum ? Birisi bu durumun neden böyle olduğunu daha fazla açıklayabilir mi, eğer gerçekten durum buysa?
David Edwards

29

Birkaç fikir:

  • Kodunuzun yarısını kaldırın (belki yorum yaparak).

    • Sorun hala orada mı? Harika, olasılıkları daralttın! Tekrar et.

    • Sorun orada değil mi? Tamam, yorumladığınız yarısına bakın!

  • Herhangi bir sürüm kontrol sistemi kullanıyor musunuz (örn. Git)? Eğer öyleyse, git checkoutdaha yeni taahhütlerinizden bazıları. Sorun ne zaman ortaya çıktı? Sorun ilk geldiğinde tam olarak hangi kodun değiştiğini görmek için çalışmaya bakın.


Cevabınız için teşekkür ederim. yarım kaldı ve hatta benim ana .js dosyasını projeden hariç. bir şekilde hata hala oluştu. bu yüzden bu konuda çok sinir bozucuyum. ve evet, git kullanıyorum. Bu hatayı bugün farkettim. bu grup projesi haline geldiğinden beri birçok taahhüt var. derin bir kontrol yapabilir. fikirler için tekrar teşekkürler.
procatmer

@procatmer git taahhüdünü bulmak için aynı stratejiyi kullanır. Örneğin, A'nın en eski olduğu 10 taahhütüm (A, B, C, D, E, F, G, H, I, J) git checkout Eolsaydı, sorunun zaten var olup olmadığını görmek isterdim . Evet ise, taahhütlerin ilk yarısında sorunu aramaya devam edeceğim. Aksi takdirde, sorunu ikinci yarıda ararım.
therobinkim

1
@procatmer Ayrıca, ana .jsdosyanızı atladıysanız ve sorun devam ederse ... bir <script src="...">etiketle getirdiğiniz bir kütüphane olabilir ! Belki endişelenmeye değer olmayan bir şey (özellikle sadece bir uyarı olduğu için)?
therobinkim

1
Sonunda sorunun nerede olduğunu buldum. değişiklikleri izlemek için ikinci fikrinizi kullandım. ve evet, sorun harici bir .jsdosyadan geliyor . görünüşe göre, önemli. sitemi oldukça yavaşlatıyor. Her neyse, cevaplarınız ve fikirleriniz için tekrar teşekkürler.
procatmer

2
Git bisect'i ikili aramayı uygulamak için kullanabilirsiniz. Bence bu sadece hata bulma amaçlı.
pietrovismara

12

Sorunun kaynağını belirlemek için uygulamanızı çalıştırın ve Chrome'un Performans sekmesine kaydedin .

Orada çalıştırmak için uzun zaman alan çeşitli işlevleri kontrol edebilirsiniz. Benim durumumda, konsoldaki uyarılarla ilişkili olan, AdBlock uzantısı tarafından yüklenen bir dosyadan geliyordu, ancak bu sizin durumunuzda başka bir şey olabilir.

Bu dosyaları kontrol edin ve bunun bir uzantının kodu veya sizin kodunuz olup olmadığını belirlemeye çalışın. (Bu sizinse, sorununuzun kaynağını buldunuz.)


Hayır, AdBlock'um yok ve hala konsola giriyorum.
Nikola Stojaković

Performans sekmesi ile analiz etmeye çalışın ve uzun süre çalışan fonksiyonların kaynağını arayın. Bu herhangi bir şey olabilir, ancak bu sorunun kaynağını belirlemenin potansiyel bir yoludur.
Matt Leonowicz

6

Ağ sekmesinin altındaki Chrome konsoluna bakın ve yüklenmesi en uzun süren komut dosyalarını bulun.

Benim durumumda dahil ettiğim ama henüz uygulamada kullanmadığım bir dizi Açısal komut dosyası vardı:

<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>

Bunlar, "Uzun Süreli Görev" hatasının belirtilenden daha uzun süren tek JavaScript dosyalarıydı.

Tüm bu dosyalar diğer web sitelerinde hiçbir hata üretmeden çalışır ama zar zor herhangi bir işlevi vardı yeni bir web uygulaması bu "Uzun Koşu Görev" hatası alıyordum. Hata kaldırıldıktan hemen sonra durdu.

Benim en iyi tahminim, bu Açısal eklentilerin başlangıç ​​etiketleri için DOM'un giderek daha derin bölümlerine tekrar tekrar bakmasıydı - hiçbirini bulamadık, çıkmadan önce tüm DOM'dan geçmek zorunda kaldılar, bu da Chrome'un beklediğinden daha uzun sürdü - ve böylece uyarı.


6

Bu mesajın kökünü arama ve gizleme veya düğümleri (çevrimdışı) gösteren kodumda buldum. Bu benim kodum oldu:

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');
});

Performans sekmesi (profiler) yaklaşık 60 ms süren etkinliği gösterir: Chromium Performance Profiler Düzeni Yeniden Hesaplama Yeniden Akışı

Şimdi:

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'));
});

Performans sekmesi (profiler) artık olayı yaklaşık 1 ms sürdüğünü gösteriyor: Chromium profiler karanlık

Ve şimdi aramanın daha hızlı çalıştığını hissediyorum (229 düğüm).


3
Özetle, ihlali alarak, kodunuzu optimize edebildiniz ve şimdi daha iyi performans gösteriyor.
Kullanıcı olmayan kullanıcı

3

Apache Cordova kaynak kodunda bir çözüm buldum. Böyle uygularlar:

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

Basit uygulama, ancak akıllı bir yol.

Android 4.4 üzerinden kullanın Promise. Daha eski tarayıcılar içinsetTimeout()


Kullanımı:

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

Bu hile kodunu ekledikten sonra tüm uyarı mesajları kayboldu.



2

Chrome Canary (veya Beta) kullanıyorsanız, 'İhlalleri Gizle' seçeneğini işaretlemeniz yeterlidir.

Chrome 56 Konsolunda İhlalleri Gizle Onay Kutusu


1

Bu, Google Chrome'un Verbose günlüğe kaydetme düzeyinin etkinleştirildiğini .

Hata mesajı örneği:

uyarının ekran görüntüsü

Açıklama:

Yeniden akış, belgenin bir kısmını veya tamamını yeniden oluşturmak amacıyla belgedeki öğelerin konumlarını ve geometrilerini yeniden hesaplamaya yönelik web tarayıcısı işleminin adıdır. Yeniden akış tarayıcıda bir kullanıcı engelleme işlemi olduğundan, geliştiricilerin yeniden akış süresinin nasıl iyileştirileceğini ve çeşitli belge özelliklerinin (DOM derinliği, CSS kural verimliliği, farklı stil değişiklikleri türleri) yeniden akış üzerindeki etkilerini anlamaları yararlıdır zaman. Bazen belgedeki tek bir öğenin yeniden düzenlenmesi, üst öğelerinin ve onu izleyen öğelerin yeniden düzenlenmesini gerektirebilir.

Orijinal makale: Tarayıcı yeniden akışını en aza indirme UX Developer, Lindsey Simon tarafından developers.google.com adresinde yayınlandı.

Ve bu link uyarı üzerine daha fazla bilgi için düzen profilleri (leylak bölgeler) Google Chrome Performans profilcisine sizi verir.


0

Bu iş parçacığı olarak görüşlerimi buraya ekleyerek konuyla ilgili "git" stackoverflow soru oldu.

Benim sorunum bir Malzeme-UI uygulamasındaydı (erken aşamalar)

  • özel Tema sağlayıcısının yerleştirilmesinin nedeni

sayfanın oluşturulmasını zorlayan bazı hesaplamalar yaptığımda (bir bileşen, "sonuçları göster", diğerlerinde ayarlananlara, "giriş bölümlerine" bağlıdır).

"Sonuç bileşenini" yeniden oluşturmaya zorlayan "durumu" güncelleyene kadar her şey yolundaydı. Buradaki ana sorun , aynı oluşturucuda (App.js / return ..) bir malzeme-ui teması ( https://material-ui.com/customization/theming/#a-note-on-performance ) vardı. "sonuç bileşeni" olarak, SummaryAppBarPure

Çözüm , ThemeProvider'ı bir seviye yukarı kaldırmak (Index.js) ve Uygulama bileşenini buraya sarmaktı, böylece ThemeProvider'ı yeniden hesaplamaya ve / yerleşim / yeniden akıtmaya zorlamıyordu.

önce

App.js'de:

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

        <SummaryAppBarPure
//...

index.js içinde

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

sonra

App.js'de:

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

        <SummaryAppBarPure
//...

index.js içinde

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

-2

Zorunlu yeniden akıtma genellikle yürütme bitiminden önce birden çok kez çağrılan bir işleve sahip olduğunuzda olur.

Örneğin, sorun bir akıllı telefonda olabilir, ancak klasik bir tarayıcıda olmayabilir.

setTimeoutSorunu çözmek için a kullanmanızı öneririm .

Bu çok önemli değil, ama tekrar ediyorum, fonksiyon 50 ms'den fazla sürdüğünde değil, bir işlevi birkaç kez çağırdığınızda ortaya çıkar. Bence cevaplarınız yanlış.

  1. 1'e 1 çağrıları kapatın ve hala hata verip vermediğini görmek için kodu yeniden yükleyin.
  2. Hataya ikinci bir komut dosyası neden olursa setTimeOut, ihlalin süresine bağlı olarak bir komut dosyası kullanın .

Bu bir çözüm değil. Orijinal soruya bir yorum olarak bırakılması daha iyi bir öneri.
Paul-Sebastian Manole

-6

Bu bir hata değildir, sadece basit bir mesajdır. Bu mesajı değişikliğini yürütmek için
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">(örnek)
için
<!DOCTYPE html>(Firefox kaynak bu beklemek)

mesajı Google Chrome 74 ve Opera 60 gösterildi. Değiştirdikten sonra açıktı, 0 ayrıntılı.
Bir çözüm yaklaşımı


5
Sadece bazı tavsiyeler: Cevabınızın sorularla bir ilgisi yok. Cevabınızı düzeltin veya kaldırın. Soru "Chrome tarayıcı konsolu neden bir ihlal uyarısı gösteriyor" idi. Yanıt, daha yeni Chrome tarayıcılarında, web sayfası JS yürütülürken aşırı tarayıcı yeniden akışlarına neden olursa sizi uyaran bir özellik olmasıdır. Daha fazla bilgi için lütfen Google'ın bu kaynağına bakın .
Paul-Sebastian Manole
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.