Повторная валидация в Ajv опирается на принцип отделения этапа разбора схемы от этапа выполнения проверки. Каждая JSON Schema один раз компилируется в оптимизированную функцию-валидатор. Дальнейшие вызовы этой функции выполняются без повторного анализа структуры схемы, что критично для производительности при частых проверках.
Ключевой момент заключается в том, что вызов
ajv.validate() с передачей схемы каждый раз инициирует
повторную компиляцию, если схема не была предварительно зарегистрирована
или закэширована. Это создаёт значительные накладные расходы в сценариях
с высокой частотой валидации.
Правильный подход строится вокруг явного разделения:
import Ajv from "ajv";
const ajv = new Ajv();
const schema = {
type: "object",
properties: {
id: { type: "number" },
name: { type: "string" }
},
required: ["id", "name"]
};
const validate = ajv.compile(schema);
validate({ id: 1, name: "A" });
validate({ id: 2, name: "B" });
Компилированная функция становится основным инструментом повторной валидации, исключая повторный разбор схемы.
Механизм addSchema позволяет регистрировать схемы внутри
экземпляра Ajv с последующим доступом по $id. Это устраняет
необходимость повторной компиляции и облегчает повторное
использование.
const ajv = new Ajv();
ajv.addSchema({
$id: "userSchema",
type: "object",
properties: {
age: { type: "number" }
}
});
const validate = ajv.getSchema("userSchema");
validate({ age: 30 });
validate({ age: 40 });
Использование $id формирует внутренний реестр
валидаторов. При повторных вызовах не происходит повторной компиляции,
если схема уже зарегистрирована.
Создание нового экземпляра Ajv для каждой операции валидации приводит к полной потере кэша компиляции. Внутренние оптимизации Ajv, включая:
$ref;работают только в пределах одного экземпляра.
Сценарий с повторной инициализацией:
function validateData(data) {
const ajv = new Ajv();
const validate = ajv.compile(schema);
return validate(data);
}
создаёт максимальные накладные расходы, так как компиляция повторяется при каждом вызове.
Структура схемы напрямую влияет на стоимость каждой повторной валидации. Некоторые конструкции увеличивают вычислительную сложность:
anyOf и oneOf;pattern с регулярными выражениями
высокой сложности;$ref на удалённые схемы;allOf композиции.При интенсивной повторной валидации предпочтительны плоские схемы с минимальной вложенностью.
Особое внимание имеет параметр additionalProperties. Его
отсутствие или неявное поведение может увеличивать количество проверок
на каждом объекте.
Ряд опций Ajv влияет на скорость повторных вызовов валидатора.
Удаление дополнительных свойств может добавлять дополнительную обработку при каждом вызове.
const ajv = new Ajv({ removeAdditional: true });
При частой валидации это приводит к модификации входного объекта, увеличивая стоимость операции.
Приведение типов увеличивает количество операций во время каждой проверки:
const ajv = new Ajv({ coerceTypes: true });
При повторных проверках с неизменной структурой данных выгоднее предварительно нормализовать данные вне валидатора.
Строгий режим увеличивает количество проверок схемы, но не влияет на уже скомпилированный валидатор. Однако при добавлении схем в рантайме возможны дополнительные расходы.
При обработке массивов объектов ключевым фактором становится переиспользование одной и той же функции валидатора.
Антипаттерн:
data.map(item => ajv.validate(schema, item));
Каждый вызов validate с передачей схемы может приводить
к повторной компиляции или дополнительному поиску схемы.
Оптимизированный вариант:
const validate = ajv.compile(schema);
for (const item of data) {
validate(item);
}
Дополнительное ускорение достигается за счёт отказа от промежуточных вызовов и минимизации аллокаций.
Ajv поддерживает прекращение проверки при первой ошибке. Это особенно важно при повторных проверках больших объектов, где полный обход схемы не всегда необходим.
const ajv = new Ajv({ allErrors: false });
Режим раннего выхода снижает среднее время повторной валидации, особенно при работе с невалидными данными.
Ajv способен генерировать код валидаторов, который выполняется быстрее интерпретируемых проверок. Это особенно эффективно при многократной повторной валидации одного и того же типа данных.
const ajv = new Ajv({ code: { optimize: true } });
const validate = ajv.compile(schema);
Сгенерированная функция минимизирует накладные расходы на ветвления и проверки, заменяя их на предрасчитанную логику.
Наиболее частые источники деградации производительности:
validate(schema, data) вместо заранее
скомпилированного валидатора;В высоконагруженных системах валидаторы часто выносятся в отдельный слой кэширования:
Такой подход полностью устраняет затраты на повторную компиляцию и обеспечивает стабильное время валидации независимо от количества вызовов.