Нарушение длительной работы задачи JavaScript заняло xx МС

недавно я получил такое предупреждение, и это мой первый раз получаю это:

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

Я работаю над групповым проектом, и я понятия не имею, откуда он исходит. раньше такого не случалось. Внезапно он появляется, когда кто-то еще участвует в проекте. Как найти, какой файл / функция вызывает такое предупреждение? Я искал ответ, но в основном о решении о том, как его решить. Я не смогу решить ее, если даже не смогу найти источник ... проблема.

Примечания: в этом случае предупреждение появляется только на chrome. Я попытался использовать Edge, не получил подобных предупреждений. Я еще не тестировал его на mozilla.

обновление : Я даже получаю ошибку jquery.min.js говорю:

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

11 ответов


Update: Chrome 58 + по умолчанию скрыл эти и другие отладочные сообщения. Чтобы отобразить их, нажмите стрелку рядом с "Info" и выберите "Verbose".

Update 2: Chrome 57 по умолчанию включен "скрыть нарушения". Чтобы включить их снова, вам нужно включить фильтры и снять флажок "скрыть нарушения".

внезапно появляется, когда кто-то еще участвует в проекте

Я думаю, что, скорее всего, вы обновили до Хром 56. Это предупреждение-замечательная новая функция (imo) - пожалуйста, выключите ее, только если вы в отчаянии, и ваш оценщик заберет у вас метки. Основные проблемы существуют в других браузерах, но браузеры просто не говорят вам, что есть проблема. Билет Chromium здесь, но на самом деле нет никакого интересного обсуждения: https://bugs.chromium.org/p/chromium/issues/detail?id=662497

эти сообщения являются предупреждениями, а не ошибками потому что это не вызовет серьезных проблем. Это может привести к тому, что кадры будут отброшены или иначе вызовут менее гладкий опыт.

их стоит исследовать и исправить, чтобы улучшить качество вашего приложения, однако. Способ сделать это-обратить внимание на то, какие обстоятельства появляются сообщения, и выполнить тестирование производительности, чтобы сузить область возникновения проблемы. Самый простой способ начать тестирование производительности-вставить код, например это:

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

    // Do the normal stuff for this function

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

Если вы хотите получить более продвинутый, вы также можете использовать профилировщик в Chrome : https://developers.google.com/web/tools/chrome-devtools/rendering-tools/

или использовать библиотеку бенчмаркинга, как этот: https://benchmarkjs.com/

как только вы нашли код, который занимает много времени (50 мс-это порог Chrome), у вас есть несколько вариантов:

  1. вырезать некоторые/все из этой задачи это может оказаться излишним!--35-->
  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 здесь:

http://blog.carbonfive.com/2013/10/27/the-javascript-event-loop-explained/


это просто предупреждения, как все упоминали. Однако, если вы заинтересованы в их разрешении (что вы должны), вам нужно сначала определить, что вызывает предупреждение. Нет никакой причины, по которой вы можете получить предупреждение о принудительном оплавлении.
Кто-то создал список для некоторых возможных вариантов. Вы можете следить за дискуссией для получения дополнительной информации.
Вот суть возможных причин ... --88-->

какие силы макет / reflow

все приведенные ниже свойства или методы при запросе / вызове JavaScript, запустит браузер для синхронного вычисления стиль и макет*. Это также называется reflow или макет бьется, и общая производительность.

элемент

Метрики коробка
  • 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() запускает двойной принудительное макет (источник)
Также…

getComputedStyle

window.getComputedStyle() как правило, принудительно стиль recalc (источник)

window.getComputedStyle() заставит макет, а также, если любой из верно следующее:

  1. элемент находится в теневом дереве
  2. есть медиа-запросы (связанные с viewport). Конкретно, одно из следующих: (источник) * min-width, min-height, max-width, max-height, width, height * aspect-ratio, min-aspect-ratio, max-aspect-ratio
    • device-pixel-ratio, resolution, orientation
  3. запрошенное свойство является одним из следующих: (источник)
    • 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

  • довольно много; не исчерпывающий список , но Тони Gentilcore 2011 года запуск Список указал на несколько.

contenteditable

  • много и много вещей, ...включая копирование изображения в буфер обмена (источник)

узнать больше здесь.

обновление:

robocat комментарии

больше фона: исходный код Chromium из оригинальный вопрос и а обсуждение API производительности для предупреждения.


пара идей:

  • удалите половину вашего кода (возможно, комментируя его).

    • проблема все еще существует? Отлично, вы сузили возможности! Повторять.

    • проблема не существует? ОК, посмотри на половину закомментирован!

  • используете ли вы какую-либо систему управления версиями (например, Git)? Если так, то git checkout некоторые из ваших последних коммитов. Когда была введена проблема? Посмотрите на фиксацию, чтобы увидеть, какой именно код изменился, когда проблема впервые появилась.


посмотрите в консоли Chrome на вкладке Сеть и найдите скрипты, которые загружаются дольше всего.

в моем случае был набор угловых добавлений к скриптам, которые я включил, но еще не использовал в приложении:

<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, загрузка которых заняла больше времени, чем указано в ошибке" длительная задача".

все эти файлы запускаются на других моих сайтах без каких-либо ошибок, но я получал это Ошибка "Long Running Task" в новом веб-приложении, которое практически не имело функциональности. Ошибка остановлена сразу после удаления.

мое лучшее предположение заключается в том, что эти угловые дополнения рекурсивно смотрели во все более глубокие разделы DOM для своих начальных тегов - не найдя ни одного, они должны были пересечь весь DOM перед выходом, что заняло больше времени, чем ожидает Chrome - таким образом, предупреждение.


Это может быть из Chrome 56 beta, если вы его используете.

но это не в журнале изменений:https://blog.chromium.org/2016/12/chrome-56-beta-not-secure-warning-web.html

вы можете скрыть это в панели фильтров консоли с помощью скрыть нарушения.


Я добрался до консоли

2 щелкните значок фильтра рядом (флажок" сохранить журнал")

3 клеща "Скрыть Нарушения" флажок


редактировать

эта функция удалена из Chrome 58

измените раскрывающийся список уровень ведения журнала на подробный, чтобы увидеть нарушения.


в моем случае я обнаружил, что это было вызвано Adblock.

Я запустил свое приложение и записал его в производительность в Chrome.

здесь вы можете проверить различные функции, которые заняли много времени. Тот, который corelated с предупреждениями в консоли был из файла, который был загружен расширением Adblock.

проверьте эти файлы и попробуйте определить, если это какой-то код расширения или ваш


Если вы используете chrome canary, просто проверьте опцию "скрыть нарушения".посмотреть здесь


Я нашел решение в исходном коде 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
});

после вставки этого кода трюка все предупреждающие сообщения исчезают.


Я нашел корень этого сообщения в мой код. Функциональность: поиск, который скрывает / показывает узлы (в автономном режиме). Было:

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

На вкладке Производительность (профилировщик): Chromium performance profiler layour recalculation reflow

теперь:

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

На вкладке Производительность (профилировщик): Chromium profiler dark

и я чувствую, что теперь поиск работает быстрее (229 узлов).


вы должны иметь повторный селектор класса, искали repeteatedly с помощью JavaScript. Если что-то должно использовать id, используйте его как id, а не как класс. Это случилось со мной.