Консоль и точки останова
Карточки оформлены правильно, но кнопка общей длительности показывает странное число. В данных двух курсов указаны 60 и 48 минут, значит ожидается 108. Чтобы понять ошибку, полезно посмотреть не только конечный текст, но и значения в момент вычисления.
Продолжим отдельный локальный пример из lesson-19 архива. CSS здесь уже исправлен, а вычисление специально оставлено неправильным. Сервер, программа и ручное браузерное упражнение не выполнялись; результаты являются ожидаемыми для подготовленных исходников.
Сначала воспроизводимое действие
Начальный HTML сразу содержит две карточки. У них атрибуты data-minutes="60" и data-minutes="48". Нажмите «Показать длительность» до загрузки данных через форму. Это уточнение исключает влияние сетевого запроса и позволяет читать один небольшой обработчик.
В исходном JavaScript получаются значения атрибутов и складываются через reduce:
const values = [...list.querySelectorAll(".course-card")]
.map(item => item.dataset.minutes);
const total = values.reduce((sum, value) => sum + value, 0);
duration.textContent = `Общая длительность: ${total} мин.`;
Это фрагмент обработчика кнопки #total; полный файл лежит в start/public/app.js. Значения dataset являются строками. Поэтому первое действие выполняется как 0 + "60", затем к полученной строке добавляется "48". Ожидаемый неправильный текст — «Общая длительность: 06048 мин.». Начальный ноль тоже участвует в конкатенации.
Прежде чем искать решение, запишите действие и значение. Формулировка «иногда неправильная длительность» смешивает множество условий. «После первого открытия, до сетевой загрузки, кнопка показывает 06048 вместо 108» уже задаёт конкретный сценарий. При другом наборе карточек ожидаемый результат потребуется пересчитать.
Остановка перед вычислением
Откройте Sources и найдите загруженный app.js нашей лаборатории. Установите точку останова на строке объявления total. Затем снова нажмите кнопку. Код должен остановиться до выполнения этой строки. На этот момент values уже содержит данные, а total ещё не вычислен.
Руководство Chrome по отладке описывает точки останова и просмотр переменных. В нашем примере остановка нужна, чтобы связать видимое значение с конкретными входными данными обработчика, а не просто добавить несколько случайных сообщений в консоль.
В Scope или консоли, находясь на остановленной строке, рассмотрите values, typeof values[0] и typeof values[1]. Ожидаются массив строк и два значения "string". Это наблюдение объясняет поведение оператора. Сам текст цифр ещё не делает значение числом: тип определяется тем, каким способом данные получены.
values
values.map(value => typeof value)
values.reduce((sum, value) => sum + Number(value), 0)
Последнее выражение является временной пробой в консоли остановленного обработчика. Оно должно дать 108 для наших двух корректных строк. Такая проба не исправляет исходный файл автоматически и не подтверждает, что преобразование подходит любым неизвестным данным.
Правка в сохраняемом файле
В public/app.js замените только выражение редукции:
const total = values.reduce((sum, value) => sum + Number(value), 0);
Остальной обработчик и сетевой код сохраняются. В expected/public/app.js находится полный исправленный файл. Для нашей модели строки длительности заданы как корректные неотрицательные числа, поэтому преобразование имеет однозначный смысл. В производственном приложении формат и допустимый диапазон нужно проверять на границе данных.
После будущей перезагрузки ожидается правильный итог 108. Снимите точку останова или продолжите выполнение, чтобы не принять остановленный интерфейс за зависшую кнопку. Отладочные условия являются частью окружения: оставленная пауза может изменить наблюдение даже при уже исправленном исходнике.
Можно также выбрать тему «Публикация» и загрузить её. По договору лаборатории там пока нет курсов; после успешного запроса список становится пустым. Для пустого массива reduce с начальным нулём ожидается итог 0. Это второй осмысленный вариант того же вычисления, а не новая несвязанная задача.
Консоль как контекст исполнения
Консоль выполняет JavaScript в выбранном контексте страницы. Когда обработчик остановлен, доступны его локальные значения. После продолжения эти имена могут уже не быть доступны в том же виде. Поэтому ответ на выражение следует связывать с моментом остановки и выбранной вкладкой, а не воспринимать как самостоятельный журнал всех прошлых состояний.
Не вставляйте в консоль неизвестный код с чужой страницы ради «быстрого исправления». В нашем уроке выражения короткие и читают учебные значения. Они не отправляют данные и не меняют аккаунт. Любая команда с сетевым вызовом или записью в хранилище уже имеет другой эффект, который нужно понимать отдельно.
Если остановка срабатывает в другом обработчике, проверьте путь файла и стек вызовов. На странице могут работать расширения или дополнительные скрипты. Подготовленная лаборатория предназначена для отдельного чистого учебного профиля и содержит один модуль приложения, что уменьшает число посторонних причин.
При чтении результата полезно назвать единицу измерения. Число 108 означает минуты двух показанных курсов; оно не является количеством уроков или временем загрузки страницы. Подпись интерфейса делает этот смысл явным. Если позже длительность хранится в секундах, одной числовой конверсии уже недостаточно: понадобится согласованное изменение данных и отображения. В нашем учебном договоре единица одинакова в HTML и API, поэтому повторная загрузка сохраняет смысл вычисления. Это объясняет, почему исправление остаётся узким. Мы меняем операцию над известными значениями, а не источник фактов о курсе. Для заметки об ошибке укажите и тип, и единицу: строковые минуты складывались как текст, после преобразования ожидается числовая сумма.
Причина и граница исправления
Числовое преобразование исправляет заданную ошибку сложения. Оно не решает автоматически проблему отсутствующего data-minutes, значения "много" или отрицательной длительности. Например, Number от неподходящей строки может дать NaN, и итог останется некорректным. Здесь мы явно ограничили исходные данные, чтобы сосредоточиться на различии строки и числа.
Также обработчик считает текущие карточки DOM, а не полный каталог на сервере. После фильтрации сумма относится к показанному списку. Это часть поведения страницы. Если требование заключалось бы в сумме всех курсов независимо от фильтра, менять пришлось бы сам источник расчёта, а не только тип значения.
Для передачи решения коллеге достаточно описать входные данные, неправильный результат, обнаруженный тип и узкую правку. Не нужно выдавать временное вычисление консоли за сохранённый и опубликованный код. В нашей текущей работе подготовлены только источники и ожидаемые состояния.
Конечный результат урока — обработчик, который для двух заданных карточек должен показывать 108 минут, а для пустого списка — 0. Мы нашли причину через данные в момент выполнения и перенесли решение в исходник. В следующем уроке прочитаем сетевой запрос формы и сопоставим его с ответом локального API.