Как использовать try-catch для обработки ошибок при парсинге JSON в JavaScript
Что проверяют
Знаете ли вы, что JSON.parse на битой строке бросает синхронное исключение, и умеете ли поймать ровно его, не спрятав заодно чужие ошибки. Следом часто спрашивают про await response.json() и про то, почему try вокруг промиса без await ничего не ловит.
Как отвечать
Покажите короткую обёртку и объясните решения в ней:
- узкий
try: внутри только самJSON.parse, дальнейшая логика снаружи. ИначеcatchпоймаетTypeErrorиз вашего же кода и выдаст его за «сломанный JSON»; - проверка типа ошибки:
if (!(e instanceof SyntaxError)) throw e. Всё, что не относится к разбору, пробрасывайте дальше; - однозначный результат: возвращать
nullпри ошибке плохо, потому что строка"null"это валидный JSON и тоже даётnull. Надёжнее вернуть объект вида{ ok: true, value }или{ ok: false, error }, либо явный дефолт; - TypeScript: в режиме
strictпеременная вcatchимеет типunknown, поэтому передe.messageтип сначала сужают. Если объект ошибки не нужен, пишут простоcatch {}.
Отдельно про сеть. await res.json() при невалидном теле отклоняет промис с SyntaxError, и поймать это можно только с await внутри try. Типичная причина: сервер вернул HTML-страницу ошибки, отсюда Unexpected token '<'. Поэтому сначала проверяют res.ok и заголовок Content-Type, а уже потом разбирают тело.
И последний шаг: успешный JSON.parse не гарантирует нужную форму данных. Для внешнего ввода добавляют проверку схемой, например через zod и safeParse.
Где спотыкаются
Заворачивают в try всю функцию целиком. Ошибка в обращении к полю превращается в сообщение «неверный формат», и отладка идёт по ложному следу.
Пишут try { fetch(url).then(r => r.json()) } catch {} и удивляются, что ошибка всплывает как необработанный отказ промиса. Без await исключение возникает уже после выхода из блока.
Забывают про localStorage: getItem возвращает null для отсутствующего ключа, JSON.parse(null) молча отдаёт null, а следующее обращение к .items падает уже вне всякого try.