В основе работы ESLint лежит последовательный пайплайн обработки исходного кода: парсинг, построение AST (абстрактного синтаксического дерева), обход дерева и выполнение набора правил. Именно последний этап оказывает наибольшее влияние на итоговую скорость анализа.
Каждое правило представляет собой отдельную функцию-обработчик, подписанную на определённые типы узлов AST. При увеличении количества правил растёт число подписок на события обхода дерева, а значит увеличивается количество проверок на каждом узле. Даже если правило не выполняет сложной логики, сам факт его вызова добавляет накладные расходы.
Ключевой момент заключается в том, что стоимость анализа определяется не только количеством правил, но и суммарной частотой их срабатывания на узлах дерева.
Поведение системы в простейшей модели можно описать как линейное:
Общая нагрузка стремится к произведению N × M при условии, что каждое правило реагирует на схожий набор событий.
Однако реальная картина сложнее:
Несмотря на оптимизации, увеличение количества активных правил почти всегда приводит к росту времени анализа.
Правила в ESLint неоднородны по стоимости выполнения.
К ним относятся проверки, которые:
Примеры логики:
Такие правила имеют минимальную стоимость на каждый узел, но при их большом количестве накопленный эффект становится заметным.
Сюда относятся проверки, которые:
Особенно затратны правила, связанные с:
Один такой rule может быть дороже десятков простых.
Плагины существенно увеличивают количество активных правил. При подключении популярных наборов:
Критический фактор — не только общее число правил, но и их перекрытие по зонам AST. Если несколько правил реагируют на один и тот же тип узла, каждый узел обрабатывается многократно разными обработчиками.
Под плотностью правил понимается количество правил, активных на один тип узла.
Пример:
CallExpressionIdentifierMemberExpressionЧем выше плотность, тем больше микрозатрат на один проход дерева. Даже при оптимальном алгоритме обхода AST увеличивается число вызовов функций, проверок условий и выделений памяти под контекст выполнения.
Конфигурация ESLint влияет не только на включённые правила, но и на механизм их регистрации.
Отключённые правила:
Их наличие в конфигурации не увеличивает нагрузку.
Некоторые конфигурации включают правила через условные механизмы:
В таких случаях увеличивается стоимость инициализации, но не всегда растёт runtime нагрузка на каждый файл.
Время анализа одного файла можно разложить на компоненты:
При увеличении количества правил особенно растёт четвёртый этап. При этом первые три остаются относительно стабильными.
Если рассматривать большие проекты, то основная деградация происходит именно на этапе применения правил, а не парсинга.
Механизм cache в ESLint снижает повторную стоимость анализа неизменённых файлов, но не устраняет влияние количества правил.
Особенности:
Таким образом, большое количество правил косвенно уменьшает эффективность кэширования.
Во время обхода AST один узел может быть обработан десятками правил. Каждый обработчик:
В итоге возникает конкуренция за:
При увеличении числа правил растёт вероятность повторных вычислений одного и того же контекста.
Некоторые правила требуют дополнительных проходов или сложного анализа:
Такие правила могут существенно увеличивать время анализа даже при небольшом их количестве. Влияние количества правил здесь нелинейно: добавление одного сложного правила иногда эквивалентно добавлению десятков простых.
Хотя ESLint не выполняет правила строго последовательно в смысле блокировки, порядок и группировка влияют на:
Группировка тяжёлых правил в отдельных конфигурациях может уменьшить перекрёстные затраты, так как уменьшает число одновременных активных подписчиков на одни и те же узлы AST.
В крупных кодовых базах влияние количества правил проявляется сильнее:
Даже линейный рост правил приводит к заметному увеличению общего времени линтинга, особенно при отсутствии агрессивного кеширования и разделения конфигураций по модулям проекта.