Cannot read properties of undefined - разбор причин на витрине
Скрипт витрины падает в консоли браузера с сообщением про чтение свойства у неопределённого значения. Разбираем причины по убыванию частоты.
С чего начать
Смотрим, что именно оказалось неопределённым:
console.log(typeof BX, typeof BX.UI, typeof window.VendorGallery);// undefined у любого из них означает неподключённое расширение или свой файлПервое, что проверяют на витрине, - подключены ли нужные библиотеки на конкретной странице. Половина таких ошибок объясняется тем, что расширение подключено на одной странице, а скрипт работает на другой.
Проверяем, существует ли узел разметки:
const node = document.querySelector('.js-gallery');console.log(node); // null означает, что разметки ещё или уже нетСкрипт, подключённый в шапке страницы, выполняется раньше разметки блока. Узел при этом ещё не создан, и обращение к его свойствам падает с той же самой ошибкой.
Печатаем ответ сервера целиком:
BX.ajax.runComponentAction('vendor:gallery', 'load', { mode: 'class' }) .then((response) => console.log(JSON.stringify(response)));// полезная нагрузка лежит в поле данных, а ошибки приходят отдельным спискомСмотрим, какой файл скрипта реально отдан браузеру:
curl -s https://example.com/catalog/ | grep -oE 'src="[^"]*(gallery|kernel)[^"]*"' | head# объединение статики отдаёт один общий файл, и в нём может лежать старая версияОтключаем объединение статики на время разбора:
printf("объединение js=%s css=%s\n", \COption::GetOptionString('main', 'optimize_js_files'), \COption::GetOptionString('main', 'optimize_css_files'));// на время разбора объединение выключают, потом обязательно возвращаютПричины
-
Расширение или свой файл не подключены примерно 30% случаев
ПризнакВ консоли неопределён сам объект библиотеки, а не его отдельное свойство.
ПроверкаПечатаем тип нужного объекта в консоли именно на той странице, где падает скрипт.
Что делатьПодключаем расширение или свой файл на этой странице средствами платформы, а не тегом.
-
Узла разметки ещё нет на момент запуска примерно 20% случаев
ПризнакОшибка возникает сразу при загрузке страницы, а по кнопке всё работает.
ПроверкаПечатаем результат поиска узла: пустое значение сразу подтверждает версию.
Что делатьПереносим запуск после разметки блока или откладываем его до готовности документа.
-
Ответ сервера отличается от ожидаемого примерно 20% случаев
ПризнакОшибка появляется после запроса к серверу, а не при загрузке страницы.
ПроверкаПечатаем ответ целиком и сверяем структуру полей с тем, что ждёт код.
Что делатьЧитаем полезную нагрузку из поля данных ответа и обрабатываем список ошибок отдельно.
-
Опечатка или переименованное поле примерно 15% случаев
ПризнакОшибка появилась сразу после правки шаблона или переименования параметра.
ПроверкаСравниваем имя поля в разметке, в коде скрипта и в ответе сервера построчно.
Что делатьПриводим имена к одному виду и добавляем проверку наличия поля перед обращением.
-
Браузер получил старую версию файла примерно 15% случаев
ПризнакОшибка воспроизводится не у всех и пропадает после жёсткого обновления страницы.
ПроверкаСмотрим адрес отданного файла и его метку версии в исходном коде страницы.
Что делатьСбрасываем объединение статики и кэш, чтобы браузер получил свежую версию файла.
Частые вопросы
Почему ошибка воспроизводится не у всех?
Обычно дело в кэше браузера или в объединённом файле статики. У части посетителей лежит старая версия скрипта, у остальных - новая.
Как понять, где именно падает код?
По стеку вызовов в консоли: он показывает файл и строку. При объединении статики строку смотрят в исходном файле, а не в общем.
Помогают ли проверки перед обращением?
Да, они превращают падение скрипта в тихий пропуск блока. Причину при этом всё равно ищут: тихий пропуск - не решение, а смягчение.
Почему на стенде всё работает?
На стенде обычно выключено объединение статики и кэш браузера чистый. Проверять такие ошибки надо в тех же условиях, что и на бою.
Стоит ли откладывать весь код до готовности документа?
Нет, это замедляет отклик страницы. Откладывают только то, что действительно зависит от разметки, а остальное запускают сразу.
Смежное
- Свои расширения JS - оглавление подтемы
- Расширение JS не подключается: разбор причин - если объекта нет вовсе
- Клиентский код в шаблоне: инициализация, делегирование, дубли - как писать код шаблона правильно
- Не работает AJAX-запрос: разбор причин - когда падает не скрипт, а запрос
- Стили и скрипты в шаблоне: подключение, порядок, кэш - объединение статики и метка версии
- Правки шаблона компонента не видны: разбор причин - соседний разбор про кэш
- Ядро BX и AJAX - устройство клиентского ядра