Валидация данных в Zod изначально синхронна: схемы описывают
структуру, типы и ограничения, которые могут быть проверены немедленно.
Однако в реальных сценариях часть проверок требует асинхронных операций
— запросов к базе данных, внешним API, файловой системе. Для таких
случаев используются parseAsync и
safeParseAsync, которые расширяют стандартный механизм
выполнения схем, переводя его в промис-ориентированную модель.
Асинхронные схемы возникают при использовании:
refine с асинхронной функциейsuperRefine с asynctransform с асинхронной логикойМетод parseAsync выполняет полную проверку входных
данных согласно схеме и возвращает промис. В случае ошибки выполнение
прерывается с выбросом исключения.
Promise<T>ZodErrorimport { z } from "zod";
const schema = z.object({
email: z.string().email(),
id: z.string().refine(async (val) => {
const exists = await fakeDatabaseCheck(val);
return exists;
}, {
message: "ID не найден"
})
});
async function run() {
const data = await schema.parseAsync({
email: "test@mail.com",
id: "123"
});
}
В этом примере refine содержит асинхронную операцию,
поэтому использование parse невозможно — требуется
parseAsync.
При вызове происходит последовательность:
Важно, что даже если только один слой схемы содержит асинхронную логику, вся цепочка автоматически становится асинхронной.
При первом же несоответствии данных или возврате false
из refine происходит генерация ZodError.
Исключение содержит:
path)code)message)expected,
received)try {
await schema.parseAsync(input);
} catch (err) {
console.log(err.errors);
}
Особенность parseAsync: выполнение прерывается на этапе
первой критической ошибки, если схема не использует
superRefine с накоплением ошибок.
Метод safeParseAsync возвращает результат в виде
объекта, исключая необходимость обработки исключений через
try/catch.
{
success: true,
data: T
}
или
{
success: false,
error: ZodError
}
const result = await schema.safeParseAsync(input);
if (result.success) {
console.log(result.data);
} else {
console.log(result.error.issues);
}
Основное отличие — управление потоком выполнения остаётся у вызывающего кода, без исключений.
awaitАсинхронность в Zod активируется только при наличии async-операций внутри схемы.
const usernameSchema = z.string().refine(async (val) => {
const taken = await checkUsername(val);
return !taken;
}, {
message: "Имя занято"
});
Без parseAsync или safeParseAsync такой код
не выполнится корректно.
superRefine позволяет добавлять множественные ошибки и
сложную логику проверки.
const schema = z.object({
password: z.string()
}).superRefine(async (data, ctx) => {
const breached = await checkPasswordLeak(data.password);
if (breached) {
ctx.addIssue({
code: "custom",
message: "Пароль скомпрометирован"
});
}
});
При использовании superRefine асинхронность
распространяется на всю схему.
Асинхронные трансформации изменяют тип результата после валидации:
const schema = z.string().transform(async (val) => {
return await hashValue(val);
});
parseAsync в этом случае возвращает уже преобразованный
результат.
Zod допускает смешанные схемы:
В таких случаях весь pipeline автоматически становится промисом.
Асинхронная валидация добавляет накладные расходы:
Promise.allПри большом количестве refine с внешними запросами
возникает эффект «цепной задержки», особенно если нет кеширования.
Типичные проблемы:
parse вместо parseAsyncЕсли хотя бы один вложенный объект содержит async-логику, вся верхнеуровневая схема становится асинхронной:
const userSchema = z.object({
profile: z.object({
username: z.string().refine(async (val) => {
return await check(val);
})
})
});
Даже при вызове верхнего уровня требуется
parseAsync.
Асинхронные проверки в массивах выполняются параллельно:
const schema = z.array(
z.string().refine(async (val) => {
return await checkItem(val);
})
);
Каждый элемент проходит отдельную async-валидацию, агрегируемую в общий результат.
При сложных вложенных структурах safeParseAsync
сохраняет полную иерархию ошибок:
{
success: false,
error: {
issues: [
{
path: ["profile", "username"],
message: "Имя занято"
}
]
}
}
Это позволяет точно локализовать источник ошибки без исключений.
Асинхронная валидация используется в:
parseAsync чаще применяется в бизнес-логике, где ошибка
должна прерывать выполнение. safeParseAsync используется на
границах системы — API, формы, UI.
parseAsync — строгая валидация с исключениями и
прерыванием потокаsafeParseAsync — функциональная валидация с явным
результатомZodError или объект
результата