위반 오래 실행되는 JavaScript 작업에 xxms 소요


330

최근에 이런 종류의 경고가 나타 났으며, 이것이 처음입니다.

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

나는 그룹 프로젝트를 진행 중이며 어디에서 왔는지 전혀 모른다. 이것은 전에 일어난 적이 없다. 갑자기 누군가 다른 사람이 프로젝트에 참여했을 때 나타났습니다. 이 경고의 원인이되는 파일 / 함수를 어떻게 찾습니까? 나는 답을 찾고 있었지만 대부분 그것을 해결하는 방법에 대한 해결책에 대해 이야기했습니다. 문제의 원인을 찾을 수 없으면 해결할 수 없습니다.

이 경우 경고는 Chrome에만 나타납니다. Edge를 사용하려고했지만 비슷한 경고가 표시되지 않았으며 아직 Firefox에서 테스트하지 않았습니다.

나는 심지어 오류를 얻는다 jquery.min.js:

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

이 경고는 어디에 있습니까? 어떤 환경에서 작업하고 있는지 말하지 않습니다. 일부 브라우저를 가정하지만 어떤 브라우저를 가정합니까?
Sami Kuhmonen

3
@SamiKuhmonen 죄송합니다. 제 질문을 업데이트했습니다. 나는 크롬을 사용했다. Edge에서 비슷한 오류를 찾지 못했습니다.
procatmer

8
2016 년 후반에 소개 된이 경고 메시지는 Chrome에 설치 한 확장 프로그램으로 인해 나타날 수도 있다고 덧붙였습니다. 개인 모드에서 테스트하여 쉽게 확인할 수 있습니다.
Fer

1
위반이 발생한 스크립트를 표시하는 오른쪽 링크를 클릭하면 코드에서 발생하는 위치로 이동합니다.
bluehipy

Ionic 4 (Angular 8)를 사용하고 있는데 코드가 제대로 작동했습니다. 갑자기 이런 종류의 위반이 시작되었습니다. 내 목록에 데이터가 표시되지 않습니까?
Kapil Raghuwanshi

답변:


278

업데이트 : Chrome 58 이상에서는 기본적으로 이러한 디버그 메시지와 기타 디버그 메시지를 숨겼습니다. 이를 표시하려면 '정보'옆의 화살표를 클릭하고 '자세한 내용'을 선택하십시오.

Chrome 57은 기본적으로 '숨기기 위반'을 설정했습니다. 필터를 다시 켜려면 필터를 활성화하고 '위반 사항 숨기기'상자를 선택 취소해야합니다.

갑자기 다른 사람이 프로젝트에 참여했을 때 나타납니다.

Chrome 56으로 업데이트했을 가능성이 큽니다.이 경고는 훌륭한 새 기능입니다. 필자가 필사적으로 평가판을 표시하지 않을 경우에만 끄십시오. 근본적인 문제는 다른 브라우저에 있지만 브라우저는 문제가 있다고 알려주지 않습니다. Chromium 티켓이 여기 있지만 실제로 흥미로운 토론은 없습니다.

이 메시지는 실제로 큰 문제를 일으키지 않기 때문에 오류 대신 경고입니다. 프레임이 떨어지거나 덜 부드러운 느낌을 줄 수 있습니다.

그러나 응용 프로그램의 품질을 향상시키기 위해 조사하고 수정해야합니다. 이를 수행하는 방법은 메시지가 나타나는 환경에주의를 기울이고 문제가 발생한 위치를 좁히기 위해 성능 테스트를 수행하는 것입니다. 성능 테스트를 시작하는 가장 간단한 방법은 다음과 같은 코드를 삽입하는 것입니다.

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

    // Do the normal stuff for this function

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

좀 더 고급 얻고 싶은 경우에, 당신은 또한 사용할 수있는 크롬의 프로파일 러를 , 또는 같은 벤치 마크 라이브러리를 사용하게 이 일을 .

시간이 오래 걸리는 코드를 찾은 경우 (50ms는 Chrome의 임계 값임) 몇 가지 옵션이 있습니다.

  1. 불필요 할 수있는 작업의 일부 / 모두 잘라 내기
  2. 동일한 작업을 더 빠르게 수행하는 방법 파악
  3. 코드를 여러 개의 비동기 단계로 나눕니다.

(1)과 (2)는 어렵거나 불가능할 수 있지만 때로는 정말 쉬우 며 첫 번째 시도 여야합니다. 필요한 경우 항상 할 수 있어야합니다 (3). 이를 위해 다음과 같은 것을 사용합니다.

setTimeout(functionToRunVerySoonButNotNow);

또는

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

JavaScript의 비동기 특성에 대한 자세한 내용은 여기를 참조하십시오 .


16
를 사용하는 대신 제안하는 것만 performance.now()사용할 수 있습니다 console.time( developer.mozilla.org/en-US/docs/Web/API/Console/time ) console.time('UniquetLabelName') ....code here.... console.timeEnd('UniqueLabelName')
denislexic

@denislexic 것 같아요. 나는 그것이 실제로 어떤 가치를 더하는지 잘 모르겠습니다. 나는 현재 시간을 얻고 그것을 기반으로하는 기본 작업에 대해 배우는 것이 더 가치 있다고 주장합니다.
voltrevo

34
큰 답변, voltrevo! 내 질문은, 이와 같은 코드가 위반이라면 정확히 위반하는 것은 무엇입니까? Google이 적용하는 표준이 있어야하지만 그 표준은 어디서나 공개적으로 문서화되어 있습니까?
Bungler

1
@ Bungler Dunno, 참조하는 지침이 있는지 알고 싶습니다.
voltrevo

4
@ Bungler 애니메이션 코드가 초당 60 프레임 이상을 제공하지 않아 사용자 경험이 좋지 않다고 말하는 것만 추측 할 수 있습니다. .
user895400

90

이들은 모두 언급했듯이 경고입니다. 그러나 이러한 문제를 해결하는 데 관심이 있다면 먼저 경고의 원인을 식별해야합니다. 강제 리플 로우 경고를받을 수있는 이유는 없습니다. 누군가가 몇 가지 가능한 옵션에 대한 목록 을 작성했습니다 . 자세한 내용은 토론을 따라갈 수 있습니다.
가능한 이유는 다음과 같습니다.

레이아웃 / 리플 로우를 강제하는 요인

JavaScript로 요청 / 불러올 때 아래의 모든 속성 또는 메서드는 브라우저가 스타일과 레이아웃을 동기식으로 계산하도록 트리거합니다 *. 이것을 리플 로우 또는 레이아웃 스 래싱 이라고도하며 일반적인 성능 병목 현상입니다.

요소

박스 메트릭
  • elem.offsetLeft, elem.offsetTop, elem.offsetWidth, elem.offsetHeight,elem.offsetParent
  • elem.clientLeft, elem.clientTop, elem.clientWidth,elem.clientHeight
  • elem.getClientRects(), elem.getBoundingClientRect()
물건 스크롤
  • elem.scrollBy(), elem.scrollTo()
  • elem.scrollIntoView(), elem.scrollIntoViewIfNeeded()
  • elem.scrollWidth, elem.scrollHeight
  • elem.scrollLeft, elem.scrollTop또한 그들을 설정
초점
  • elem.focus()이중 강제 레이아웃을 트리거 할 수 있습니다 ( source )
또한…
  • elem.computedRole, elem.computedName
  • elem.innerText( 소스 )

getComputedStyle

window.getComputedStyle()일반적으로 스타일 재 계산을 강제합니다 ( source )

window.getComputedStyle() 다음 중 하나라도 해당되면 레이아웃을 강제합니다.

  1. 요소는 그림자 트리에 있습니다
  2. 미디어 쿼리 (뷰포트 관련 쿼리)가 있습니다. 즉, 다음 중 하나 : ( 소스 ) * min-width, min-height, max-width, max-height, width, height * aspect-ratio, min-aspect-ratio,max-aspect-ratio
    • device-pixel-ratio, resolution,orientation
  3. 요청 된 속성은 다음 중 하나입니다. ( source )
    • height, width * top, right, bottom, left * margin[ -top, -right, -bottom, -left, 또는 속기 ] 마진이 고정되어있는 경우에만. * padding[ -top, -right, -bottom, -left, 또는 속기 ] 패딩이 고정되어있는 경우에만. *transform , transform-origin, perspective-origin * translate, rotate, scale * webkit-filter, backdrop-filter * motion-path, motion-offset, motion-rotation * x, y, rx,ry

창문

  • window.scrollX, window.scrollY
  • window.innerHeight, window.innerWidth
  • window.getMatchedCSSRules() 힘만 스타일

양식

  • inputElem.focus()
  • inputElem.select(), textareaElem.select()( 소스 )

마우스 이벤트

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

문서

  • doc.scrollingElement 힘만 스타일

범위

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

SVG

편집 가능한

  • … 이미지를 클립 보드에 복사하는 것을 포함하여 많은 것들 ( source )

더 확인 여기서 하십시오 .

또한 원래 문제 의 Chromium 소스 코드 와 성능 API에 대한 토론이 있습니다. 경고 대한 설명이 있습니다.


편집 : Google PageSpeed ​​Insight 에서 레이아웃 리플 로우를 최소화하는 방법에 대한 기사도 있습니다. . 브라우저 리플 로우가 무엇인지 설명합니다.

리플 로우는 문서의 일부 또는 전부를 다시 렌더링하기 위해 문서에서 요소의 위치와 형상을 다시 계산하기위한 웹 브라우저 프로세스의 이름입니다. 리플 로우는 브라우저에서 사용자 차단 작업이므로 개발자가 리플 로우 시간을 개선하는 방법을 이해하고 리플 로우에 대한 다양한 문서 속성 (DOM 깊이, CSS 규칙 효율성, 다양한 유형 변경)의 영향을 이해하는 것이 유용합니다. 시각. 때로는 문서에서 단일 요소를 리플 로우하려면 부모 요소와 그 뒤에 오는 모든 요소를 ​​리플 로우해야 할 수 있습니다.

또한 최소화하는 방법에 대해 설명합니다.

  1. 불필요한 DOM 깊이를 줄입니다. DOM 트리에서 한 수준에서 변경하면 모든 트리 수준에서 루트까지, 수정 된 노드의 자식까지 변경 될 수 있습니다. 이로 인해 리플 로우 수행에 더 많은 시간이 소요됩니다.
  2. CSS 규칙을 최소화하고 사용하지 않는 CSS 규칙을 제거하십시오.
  3. 애니메이션과 같이 복잡한 렌더링을 변경하는 경우 흐름에서 벗어나십시오. 이를 위해 위치 절대 또는 위치 고정을 사용하십시오.
  4. 선택기 일치를 수행하는 데 더 많은 CPU 성능이 필요한 불필요한 복잡한 CSS 선택기 (특히 하위 선택기)를 피하십시오.

1
추가 배경 : 원래 문제 의 Chromium 소스 코드 및 경고 의 성능 API에 대한 토론
robocat

1
위의 내용에 따르면 단순히 element.scrollTop을 읽으면 리플 로우가 트리거됩니다. 이것은 반 직관적 인 현상으로 저를 놀라게합니다. element.scrollTop을 설정 하면 리플로가 발생하지만 그 값을 읽는 이유를 이해할 수 있습니까? 실제로 이것이 사실이라면 누군가가 왜 그런지를 더 설명 할 수 있습니까?
David Edwards

29

몇 가지 아이디어 :

  • 코드의 절반을 제거하십시오.

    • 여전히 문제가 있습니까? 좋습니다, 가능성을 좁혔습니다! 반복.

    • 문제가 없습니까? 좋아, 당신이 코멘트 절반을 봐!

  • 버전 관리 시스템 (예 : Git)을 사용하고 있습니까? 그렇다면 git checkout최근 커밋 중 일부입니다. 언제 문제가 발생 했습니까? 커밋을보고 문제가 처음 도착했을 때 변경된 코드를 정확히 확인하십시오.


답변 주셔서 감사합니다. 나는 절반을 제거하고 프로젝트에서 내 기본 .js 파일을 제외했습니다. 어떻게 든 오류가 계속 발생했습니다. 이것이 내가 너무 좌절하는 이유입니다. 네, 저는 git을 사용하고 있습니다. 나는 오늘이 오류를 깨달았습니다. 이것이 그룹 프로젝트가 된 이래로 많은 커밋이있었습니다. 심층 검사를 할 수 있습니다. 아이디어에 다시 한번 감사드립니다.
procatmer

@procatmer는 git commit을 찾는 것과 동일한 전략을 사용합니다. 예를 들어, A가 가장 오래된 10 개의 커밋 (A, B, C, D, E, F, G, H, I, J)이 git checkout E있으면 문제가 이미 존재하는지 확인해야합니다. 그렇다면 커밋의 전반부에서 문제를 계속 찾습니다. 그렇지 않으면 하반기에 문제를 찾습니다.
therobinkim

1
@procatmer 또한 메인 .js파일 을 생략 하고 문제가 지속되면 <script src="...">태그 를 통해 가져온 라이브러리 일 수 있습니다 ! 걱정할 가치가없는 것 (특히 경고 일 뿐이므로)?
therobinkim

1
나는 마침내 문제가 어디에 있는지 발견했다. 두 번째 아이디어를 사용하여 변경 사항을 추적했습니다. 그렇습니다. 문제는 외부 .js파일 에서 비롯된 것 입니다. 분명히 중요합니다. 내 사이트가 상당히 느려집니다. 어쨌든 답변과 아이디어에 다시 한번 감사드립니다.
procatmer

2
git bisect를 사용하여 이진 검색을 적용 할 수 있습니다. 나는 그것이 버그 찾기의 목적이라고 생각합니다.
pietrovismara

12

문제의 원인을 식별하려면 애플리케이션을 실행하고 Chrome의 성능 탭에 기록하십시오 .

실행하는 데 오랜 시간이 걸리는 다양한 기능을 확인할 수 있습니다. 필자의 경우 콘솔의 경고와 관련이있는 것은 AdBlock 확장 프로그램에 의해로드 된 파일에서 가져온 것이지만 귀하의 경우에는 다른 것일 수 있습니다.

이러한 파일을 확인하고 이것이 확장 코드인지 확인하십시오. (귀하의 것이면 문제의 원인을 찾았습니다.)


아니요, AdBlock이 없어 콘솔에서 계속 사용할 수 있습니다.
Nikola Stojaković

성능 탭을 사용하여 분석하고 오랜 시간 실행되는 기능의 소스를 찾으십시오. 이것은 무엇이든 가능하지만 문제의 원인을 식별 할 수있는 잠재적 인 방법입니다.
Matt Leonowicz

6

Chrome 콘솔의 네트워크 탭 아래에서로드하는 데 가장 오래 걸리는 스크립트를 찾으십시오.

제 경우에는 앱에 포함되었지만 아직 사용하지 않은 스크립트에 Angular 추가 세트가있었습니다.

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

"긴 실행 작업"오류가 지정한 시간보다로드하는 데 시간이 오래 걸린 유일한 JavaScript 파일입니다.

이러한 파일은 모두 다른 웹 사이트에서 오류없이 생성되었지만 거의 작동하지 않는 새 웹 앱에서이 "긴 실행 작업"오류가 발생했습니다. 제거 즉시 오류가 중지되었습니다.

가장 좋은 추측은 Angular 애드온이 시작 태그에 대해 점점 더 깊이있는 DOM 섹션을 재귀 적으로 찾고 있다는 것입니다.


6

내 코드 에서이 메시지의 루트를 찾았습니다.이 메시지는 노드를 검색하고 숨기거나 표시했습니다 (오프라인). 이것은 내 코드였습니다.

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

성능 탭 (프로필러)에는 약 60ms의 이벤트가 표시됩니다. 크롬 성능 프로파일 러 레이아웃 재 계산 리플 로우

지금:

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

성능 탭 (프로필러)에 약 1ms의 이벤트가 표시됩니다. 크롬 프로파일 러 어두운

그리고 검색이 더 빨리 작동한다고 생각합니다 (229 노드).


3
요약하면 위반 사항을 수신하여 코드를 최적화 할 수 있었으며 이제는 성능이 향상되었습니다.
사용자가 아닌 사용자

3

Apache Cordova 소스 코드에서 솔루션을 찾았습니다. 그들은 다음과 같이 구현합니다.

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

간단한 구현이지만 현명한 방법.

Android 4.4에서는을 사용하십시오 Promise. 구형 브라우저의 경우setTimeout()


용법:

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

이 트릭 코드를 삽입하면 모든 경고 메시지가 사라집니다.



2

Chrome 카나리아 (또는 베타)를 사용하는 경우 '위반 숨기기'옵션을 확인하십시오.

Chrome 56 콘솔에서 위반 확인란 숨기기


1

이것은 Chrome의 위반 오류이며 Verbose로깅 수준을 사용하도록 설정 .

오류 메시지의 예 :

경고의 스크린 샷

설명:

리플 로우는 문서의 일부 또는 전부를 다시 렌더링하기 위해 문서에서 요소의 위치와 형상을 다시 계산하기위한 웹 브라우저 프로세스의 이름입니다. 리플 로우는 브라우저에서 사용자 차단 작업이므로 개발자가 리플 로우 시간을 개선하는 방법을 이해하고 리플 로우에 대한 다양한 문서 속성 (DOM 깊이, CSS 규칙 효율성, 다양한 유형 변경)의 영향을 이해하는 것이 유용합니다. 시각. 때로는 문서에서 단일 요소를 리플 로우하려면 부모 요소와 그 뒤에 오는 모든 요소를 ​​리플 로우해야 할 수 있습니다.

원본 기사 : 브라우저 리플 로우 최소화 UX 개발자 인 Lindsey Simon의 developers.google.com에 의해

그리고 이것은 링크입니다 경고에 대한 추가 정보를 원하시면 레이아웃 프로파일합니다 (자주색 지역)에 Google 크롬 성능 프로파일 러에서 당신을 제공은.


0

이 글이 주제에 대한 "go to"stackoverflow 질문이므로 여기에 통찰력을 추가하십시오.

내 문제는 Material-UI 앱에서 발생했습니다 (초기 단계)

  • 사용자 정의 테마 제공자의 배치가 원인이었습니다.

페이지 렌더링을 강제로 계산했을 때 (한 구성 요소 "디스플레이 결과"는 다른 구성 요소 "입력 섹션"에 따라 달라짐)

"결과 구성 요소"를 다시 렌더링하도록 "상태"를 업데이트 할 때까지 모든 것이 정상이었습니다. 여기서 주요 문제 는 동일한 렌더러 (App.js / return ..)에 material-ui 테마 ( https://material-ui.com/customization/theming/#a-note-on-performance ) 가 있다는 것입니다 . "결과 구성 요소", SummaryAppBarPure

해결책 은 ThemeProvider를 한 단계 높이고 (Index.js) 여기에 App 구성 요소를 래핑하여 ThemeProvider가 다시 계산하고 그리거나 레이아웃 / 리플로하지 않도록하는 것입니다.

전에

App.js에서 :

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

        <SummaryAppBarPure
//...

index.js에서

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

App.js에서 :

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

        <SummaryAppBarPure
//...

index.js에서

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

-2

강제 리플 로우는 종종 실행이 끝나기 전에 여러 번 호출 된 함수가있을 때 발생합니다.

예를 들어, 스마트 폰에서는 문제가 있지만 클래식 브라우저에서는 문제가되지 않을 수 있습니다.

setTimeout문제를 해결하기 위해 a 를 사용하는 것이 좋습니다 .

이것은 매우 중요하지 않지만 반복합니다. 함수가 50ms 이상 걸리지 않고 함수를 여러 번 호출하면 문제가 발생합니다. 나는 당신이 당신의 대답에 착각했다고 생각합니다.

  1. 1 대 1 통화를 끄고 코드를 다시로드하여 여전히 오류가 발생하는지 확인하십시오.
  2. 두 번째 스크립트에서 오류가 발생 setTimeOut하면 위반 기간에 따라를 사용하십시오 .

이것은 해결책이 아닙니다. 원래 질문에 대한 의견으로 남겨 두는 것이 좋습니다.
Paul-Sebastian Manole

-6

이것은 단순한 메시지가 아니라 오류가 아닙니다. 이 메시지 변경 실행하려면
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">(예)
에을
<!DOCTYPE html>(파이어 폭스 소스이 예상)

메시지는 구글 크롬 (74)와 오페라 60에 나타내었다. 그것을 바꾼 후 명확했다.
솔루션 접근


5
조언 : 당신의 대답은 질문과 관련이 없습니다. 답을 수정하거나 제거하십시오. 문제는 "Chrome 브라우저 콘솔에 위반 경고가 표시되는 이유"였습니다. 이에 대한 대답은 최신 Chrome 브라우저의 기능으로, JS를 실행하는 동안 웹 페이지에서 과도한 브라우저 리플 로우가 발생하는 경우이를 알려줍니다. 자세한 내용 은 Google의이 리소스를 참조하십시오 .
Paul-Sebastian Manole 19
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.