Работа валидаторов в Superstruct построена на принципе композиции структур и повторного использования проверок, что делает систему гибкой, но при больших схемах и частых проверках критически важной становится оптимизация повторных вычислений. Одним из ключевых механизмов ускорения является мемоизация (memoization) — кэширование результатов работы валидаторов и структур для устранения дублирующих вычислений.
Мемоизация в контексте Superstruct применяется на уровне обёртки структур. Основная идея заключается в том, что одна и та же структура, применённая к одинаковым входным данным, не должна выполняться заново. Вместо этого результат берётся из кэша.
Функция memo принимает структурный валидатор и
возвращает его оптимизированную версию:
import { string, number, object, memo } from 'superstruct'
const User = memo(object({
id: number(),
name: string(),
}))
В данном случае структура User будет проверять входные
данные с учётом кэширования ранее обработанных значений.
Внутренне мемоизация опирается на комбинацию двух факторов:
Это означает, что мемоизация эффективна в сценариях, где:
Если структура или данные создаются заново на каждом вызове, эффективность мемоизации резко снижается, поскольку ключ кэша перестаёт совпадать.
В Superstruct важно различать два уровня оптимизации:
Обёртка memo(struct) предотвращает повторное выполнение
логики валидатора для одинаковых входных значений.
Композиция через object, array,
union уже сама по себе может быть дорогой операцией, если
схемы создаются динамически:
const makeUserStruct = () => object({
id: number(),
name: string(),
})
Каждый вызов makeUserStruct() создаёт новую структуру, и
мемоизация не сработает.
Правильный подход:
const User = memo(object({
id: number(),
name: string(),
}))
Наибольший эффект мемоизация даёт при проверке сложных вложенных структур.
Пример:
const Comment = memo(object({
id: number(),
text: string(),
}))
const Post = memo(object({
id: number(),
title: string(),
comments: array(Comment),
}))
При повторной валидации постов с идентичной структурой комментариев кэш позволяет избежать повторного обхода дерева валидаторов.
Однако есть важное ограничение: если массивы или объекты создаются заново (например, через JSON.parse), ссылки меняются, и кэш не срабатывает.
Кэш в мемоизированных структурах не использует глубокое сравнение значений. Это принципиальное решение, позволяющее сохранить производительность.
Следствия:
Это поведение важно учитывать при работе с потоками данных, приходящих из API.
В сценариях с высокой нагрузкой мемоизация даёт значительный прирост:
Особенно заметен эффект в:
Однако при нерегулярных данных с высокой вариативностью кэш может почти не использоваться, а его поддержка становится дополнительным overhead.
Мемоизация особенно эффективна в комбинации с вложенными схемами.
const Address = memo(object({
city: string(),
zip: string(),
}))
const User = memo(object({
id: number(),
address: Address,
}))
Здесь повторное использование Address позволяет избежать
повторной валидации подструктуры при обработке разных пользователей с
одинаковой схемой адреса.
const User = memo(object({
id: number(),
createdAt: new DateType(),
}))
Если new DateType() создаёт новую структуру при каждом
вызове, мемоизация теряет смысл.
validate(User, { ...user })
Оператор spread создаёт новый объект, что приводит к промаху кэша.
Не каждая структура требует мемоизации. Простые типы
(string, number) не выигрывают от неё, так как
их проверка минимальна по стоимости.
Мемоизация не изменяет семантику ошибок. Если валидация завершилась неудачно:
Это важно для предотвращения некорректного повторного использования ошибок.
При использовании пользовательских структур:
import { define, memo } from 'superstruct'
const Positive = memo(define('Positive', (value) => {
return typeof value === 'number' && value > 0
}))
мемоизация применяется на уровне результата функции-валидатора, что позволяет избегать повторного выполнения проверки для одинаковых входных значений.
Несмотря на оптимизацию, мемоизация в Superstruct имеет ряд ограничений:
Эти ограничения делают механизм полезным, но не универсальным решением для всех сценариев валидации.