Перейти к содержанию

Лабораторная работа №4 - Регулярные выражения. Разные функции. Формы, качество кода и современные подходы в web-разработке. Асинхронность и интеграция с внешними сервисами


1. Теория

1.0. Цель работы

Сформировать у обучающегося устойчивые навыки:

  • применения регулярных выражений (RegExp) для поиска, извлечения и валидации пользовательского ввода;
  • разработки форм и клиентской валидации (обязательность, формат, диапазоны, сообщения об ошибках);
  • использования встроенных и пользовательских функций обработки данных (нормализация, фильтрация, преобразования, проверки);
  • реализации асинхронного получения данных (fetch, Promise, async/await), обработки JSON и контроля ошибок (сетевые ошибки, неверный формат, пустой ответ, статус-коды);
  • соблюдения качества кода: читаемость, модульность, предсказуемость, отсутствие дублирования, “современный подход” (чистые функции, единственный источник истины, аккуратная работа с состоянием UI).

1.1. Место лабораторной работы №4 в проекте семестра

Лабораторная работа №1 создала основу:

  • репозиторий GitHub;
  • структура проекта (index.html, style.css, script.js, README.md, passport.md);
  • простая верстка под предметную область;
  • проверка подключения JavaScript;
  • формирование контекста проекта через паспорт предметной области.

Лабораторная работа №2 развила проект:

  • добавила алгоритмическое ядро;
  • ввела набор данных предметной области;
  • закрепила работу с const/let, типами данных, операторами, условиями и циклами;
  • добавила первичную демонстрацию результатов (консоль + блок вывода на странице);
  • подготовила основу для перехода к DOM и пользовательскому интерфейсу.

Лабораторная работа №3 сделала следующий шаг:

  • связала алгоритмическое ядро с интерфейсом через DOM;
  • закрепила принцип: данные → обработка → отображение;
  • ввела архитектурную дисциплину: данные в data.js, логика в logic.js, UI-слой в script.js;
  • реализовала интерактивный список и базовые сценарии управления UI.

Лабораторная работа №4 делает проект “похожим на реальный web-продукт”:

  • появляется форма для создания/редактирования записей;
  • добавляется валидация (в том числе на базе регулярных выражений);
  • появляется асинхронная интеграция с внешним сервисом (получение данных по сети), обработка JSON и ошибок;
  • укрепляется инженерный стиль: качество кода, повторное использование функций, отсутствие копипаста, единая точка принятия решений (валидация и нормализация вынесены в функции).

1.2. Регулярные выражения (RegExp): что это и зачем

Регулярные выражения — это способ описания шаблонов строк. Они используются, когда необходимо:

  • проверить, что строка соответствует формату (валидация);
  • найти фрагменты текста;
  • извлечь данные (например, id, дату, номер, код);
  • нормализовать ввод (удалить лишние пробелы, привести формат к единому виду).

В JavaScript регулярные выражения создаются:

const re1 = /abc/;              // литерал
const re2 = new RegExp("abc");  // конструктор

1.3. Базовые методы строк и RegExp: test, match, replace

Проверка соответствия (валидация):

const re = /^\d+$/;
console.log(re.test("123")); // true
console.log(re.test("12a")); // false

Извлечение совпадений:

const text = "id=25; id=30";
const ids = text.match(/\d+/g); // ["25", "30"]

Нормализация (замена):

const raw = "  Иванов   Иван  ";
const clean = raw.replace(/\s+/g, " ").trim();
console.log(clean); // "Иванов Иван"

1.4. Валидация ввода с помощью RegExp: практический смысл

Валидация — это проверка корректности данных до того, как программа примет их как “истину”.

Типовые проверки:

  • обязательность поля;
  • длина (min/max);
  • формат (дата YYYY-MM-DD, “код”, “номер”, “email” и т.д.);
  • допустимые символы;
  • диапазон чисел.

Пример формата даты:

const reDate = /^\d{4}-\d{2}-\d{2}$/;

Важно понимать: регулярное выражение проверяет формат, но не всегда проверяет смысл (например, 2026-99-99 формально подходит под шаблон). Поэтому в инженерном коде часто применяется “двухэтапная проверка”:

  1. формат RegExp;
  2. смысловая проверка (диапазоны, Date.parse, сравнение дат и т.д.).

1.5. Формы в web: submit, preventDefault, чтение значений

Форма в HTML — стандартный способ пользовательского ввода. В этой лабораторной работе форма применяется для создания/редактирования записи предметной области.

Типовая схема:

  • пользователь вводит данные;
  • нажимает “Сохранить”;
  • происходит событие submit;
  • JavaScript перехватывает submit, делает preventDefault(), валидирует ввод, затем обновляет данные и UI.

Пример:

formEl.addEventListener("submit", (e) => {
  e.preventDefault();
  // 1) чтение значений
  // 2) валидация
  // 3) обновление массива items
  // 4) renderList(...)
});

1.6. Сообщения об ошибках и качество UX валидации

Минимальные правила хорошей валидации:

  • ошибка должна быть конкретной (“Некорректная дата: ожидается YYYY-MM-DD”);
  • ошибка должна быть привязана к форме/полю;
  • если ошибок несколько — показывать список или показывать первую ошибку;
  • успешный ввод должен приводить к понятному результату (запись добавилась, список обновился, форма очистилась).

Для лабораторной работы достаточно использовать:

  • блок #message для сообщений;
  • (рекомендуется) отдельный блок #formErrors рядом с формой.

1.7. Асинхронность: Promise, async/await, сетевые запросы fetch

Асинхронный код нужен, когда результат появляется не сразу (например, при запросе по сети).

fetch(url) возвращает Promise, который выполняется позже.

Пример на async/await:

async function loadSomething() {
  const resp = await fetch("https://example.com/data.json");
  const data = await resp.json();
  return data;
}

1.8. Обработка ошибок при fetch: статус-коды, try/catch, защита от “плохого” JSON

Сетевой код обязан учитывать:

  • запрос может не выполниться (нет сети);
  • сервер может вернуть код ошибки (404, 500);
  • сервер может вернуть не-JSON или “сломанный” JSON;
  • ответ может быть пустым.

Базовый надежный шаблон:

async function safeFetchJson(url) {
  let resp;
  try {
    resp = await fetch(url);
  } catch (err) {
    return { ok: false, error: "Сетевая ошибка", details: String(err) };
  }

  if (!resp.ok) {
    return { ok: false, error: `HTTP ошибка: ${resp.status}`, details: resp.statusText };
  }

  let data;
  try {
    data = await resp.json();
  } catch (err) {
    return { ok: false, error: "Ошибка JSON", details: String(err) };
  }

  return { ok: true, data };
}

1.9. Качество кода и современные подходы

Минимальные инженерные правила для этой лабораторной работы:

  • валидация и нормализация вынесены в функции (не писать проверки прямо внутри обработчика формы);
  • UI-слой не содержит дублирования логики (обработчики вызывают функции logic.js);
  • функции делают одну задачу и имеют предсказуемые входы/выходы;
  • сообщения об ошибках формируются централизованно (единый стиль и формат);
  • асинхронный код изолирован (например, api.js или функции в logic.js) и не размазан по обработчикам.

1.10. Обзор библиотек и фреймворков

В промышленной разработке формы и валидация часто реализуются с помощью:

  • UI-фреймворков (React/Vue/Angular) — для структуры интерфейса;
  • библиотек валидации (например, schema-подходы) — для единых правил проверки;
  • HTTP-клиентов (Axios и т.д.) — для удобной работы с запросами;
  • линтеров/форматтеров (ESLint/Prettier) — для качества кода.

В рамках этой лабораторной работы подключать и устанавливать библиотеки не требуется. Задача — воспроизвести инженерный принцип: разделение ответственности, модульность, централизованная валидация, предсказуемость.


2. Задание

Цель: закрепить регулярные выражения, формы и валидацию, функции обработки данных, асинхронность, fetch/async/await, обработку JSON и контроль ошибок.


2.1. Задания на закрепление теоретического материала

Данный блок выполняется в отдельном файле practice-lr4.js (или в конце script.js, но строго отделить комментариями), чтобы студент мог продемонстрировать понимание теории до доработки предметной области.

Требования к оформлению:

  • каждая задача должна завершаться console.log(...) с выводом результата;
  • регулярные выражения обязаны применяться явно;
  • для асинхронных задач продемонстрировать результат (успех/ошибка) через console.log(...).

2.1.1. Блок A — регулярные выражения: проверка формата

Задача A1. Создать функцию isValidDateYMD(s), которая:

  • принимает строку s;
  • проверяет формат строго YYYY-MM-DD с помощью RegExp;
  • возвращает true/false;
  • продемонстрировать 3 теста: корректный формат, неверный формат, пустая строка.

Ожидаемый результат:

  • isValidDateYMD("2026-02-18") === true
  • isValidDateYMD("18.02.2026") === false
  • isValidDateYMD("") === false

Задача A2. Создать функцию isValidTitle(s), которая:

  • принимает строку s;
  • запрещает ввод “служебных” символов: <, >, {, }, ;
  • использует RegExp и возвращает true/false;
  • продемонстрировать 3 теста: обычная строка, строка с <, строка с ;.

Ожидаемый результат:

  • корректная фильтрация запрещённых символов.

2.1.2. Блок B — регулярные выражения: извлечение и нормализация

Задача B1. Создать функцию extractIds(text), которая:

  • принимает строку text;
  • извлекает все числа из строки с помощью match(/\d+/g);
  • возвращает массив чисел (не строк);
  • продемонстрировать на строке: "id=5; id=12; id=30".

Ожидаемый результат:

  • [5, 12, 30]

Задача B2. Создать функцию normalizeSpaces(s), которая:

  • заменяет любые последовательности пробельных символов на один пробел;
  • обрезает пробелы по краям;
  • использует replace(/\s+/g, " ") и trim();
  • продемонстрировать на строке " A B\t\tC ".

Ожидаемый результат:

  • "A B C"

2.1.3. Блок C — формы и валидация: модель ошибок

Задача C1. Создать функцию validateRequired(value, fieldName), которая:

  • принимает value (строка) и fieldName (строка);
  • возвращает null, если значение непустое после trim();
  • возвращает строку ошибки вида: "Поле <fieldName> обязательно" — если пустое;
  • продемонстрировать на пустой строке и на строке " ok ".

Ожидаемый результат:

  • для пустого — текст ошибки;
  • для непустого — null.

Задача C2. Создать функцию validateNumberRange(n, min, max, fieldName), которая:

  • принимает число n, границы min/max, имя поля;
  • возвращает null, если n — число и в диапазоне;
  • возвращает строку ошибки, если n не число (NaN) или вне диапазона;
  • продемонстрировать на значениях 10, -1, NaN.

Ожидаемый результат:

  • корректные сообщения об ошибках.

2.1.4. Блок D — функции обработки данных: чистые функции

Задача D1. Создать функцию buildRecordFromForm(raw), которая:

  • принимает объект “сырого ввода” raw вида: { title: string, value: string, status: string, createdAt: string }
  • нормализует title через normalizeSpaces(...);
  • преобразует value в число;
  • возвращает новый объект записи без id (id будет назначаться отдельно);
  • продемонстрировать в консоли, что value стал числом, а title нормализован.

Ожидаемый результат:

  • корректная нормализация и преобразование типов.

Задача D2. Создать функцию collectErrors(record), которая:

  • принимает объект записи (уже после преобразований);
  • использует функции из блоков A/C для проверок;
  • возвращает массив строк ошибок (пустой массив, если ошибок нет);
  • продемонстрировать минимум 2 кейса: валидный объект и объект с ошибками.

Ожидаемый результат:

  • массив ошибок и пустой массив для корректного ввода.

2.1.5. Блок E — асинхронность: Promise и async/await (2 задачи)

Задача E1. Создать функцию delay(ms), которая:

  • возвращает Promise, выполняющийся через ms миллисекунд;
  • продемонстрировать, что код “ждёт” через await delay(500) и затем печатает в консоль "done".

Ожидаемый результат:

  • в консоли видно, что "done" появляется после паузы.

Задача E2. Создать async функцию safeFetchJson(url) (по образцу из теории), которая:

  • возвращает объект { ok: true, data } или { ok: false, error, details };
  • продемонстрировать вызов на тестовом URL (любой публичный JSON) или на заведомо некорректном URL (чтобы показать обработку ошибки);
  • вывести результат в консоль.

Ожидаемый результат:

  • есть демонстрация успеха или корректной ошибки без падения программы.

2.1.6. Блок F — обработка JSON и контроль ошибок

Задача F1. Создать функцию tryParseJson(text), которая:

  • принимает строку text;
  • возвращает { ok: true, data }, если JSON.parse успешен;
  • возвращает { ok: false, error }, если парсинг не удался;
  • продемонстрировать на корректном JSON ('{"a":1}') и некорректном ('{a:1}').

Ожидаемый результат:

  • корректные результаты без исключений наружу.

Задача F2. Создать функцию normalizeApiValue(x), которая:

  • принимает значение x (может быть строкой, числом, null);
  • возвращает число:

  • если x — число → вернуть его;

  • если x — строка с числом → преобразовать;
  • иначе → вернуть 0;
  • продемонстрировать на 10, "20", null, "abc".

Ожидаемый результат:

  • предсказуемое поведение и отсутствие NaN в бизнес-логике.

2.2. Требования к модульности проекта (обязательное)

Проект должен оставаться в архитектуре:

  • data.js — данные предметной области (массив объектов);
  • logic.js — функции обработки данных, валидации и нормализации;
  • script.js — DOM, события, вызовы функций логики;
  • (допускается) api.js — функции сетевого доступа (safeFetchJson, преобразование ответа).

Правило: валидация и регулярные выражения не должны быть размазаны по обработчикам. Обработчик формы вызывает одну функцию валидации, получает результат, принимает решение.


3. Итоговая задача: “Интерактивный список записей 2.0” (ЛР1 → ЛР2 → ЛР3 → ЛР4)

Цель: продолжить развитие интерфейса проекта семестра, добавив формы, валидацию на RegExp, качество кода и асинхронную интеграцию с внешним сервисом.


3.1. Модификация верстки index.html (форма + ошибки + кнопки интеграции)

В существующую верстку проекта добавить:

  1. Форму добавления записи (минимум 4 поля) и кнопку “Сохранить”.
  2. Блок вывода ошибок формы #formErrors (список или текст).
  3. Кнопку для асинхронной интеграции, например:

  4. “Загрузить данные из внешнего сервиса”

  5. или “Обновить справочник статусов”
  6. или “Подтянуть доп. данные по записи”.
  7. (Остаётся) блок управления, контейнер списка #list, область сообщений #message.

Рекомендуемая минимальная форма:

<form id="recordForm">
  <input id="titleInput" name="title" placeholder="Название" />
  <input id="valueInput" name="value" placeholder="Value" />
  <input id="createdAtInput" name="createdAt" placeholder="YYYY-MM-DD" />
  <select id="statusInput" name="status">
    <option value="new">new</option>
    <option value="done">done</option>
  </select>
  <button type="submit">Сохранить</button>
</form>

<div id="formErrors"></div>

3.2. Требования к логике и архитектуре

  • данные находятся в data.js (массив объектов);
  • обработка данных оформлена функциями в logic.js;
  • работа с DOM, событиями и вызовами функций выполняется в script.js;
  • интерфейс обновляется через renderList(...);
  • запрещено дублировать одинаковую обработку данных в нескольких обработчиках;
  • регулярные выражения используются для валидации минимум 2 полей;
  • асинхронный fetch оформлен как функция, которая не ломает UI при ошибках.

3.3. Валидация формы

Форма должна проверяться до добавления записи в массив items.

Минимальные правила валидации:

  1. title — обязательное поле, нормализация пробелов обязательна.
  2. title — запрет символов <, >, {, }, ; (через RegExp).
  3. value — число и в диапазоне (например >= 0 и <= 1_000_000).
  4. createdAt — формат YYYY-MM-DD (RegExp) + смысловая проверка (например, Date.parse или проверка, что дата корректна).
  5. При ошибках:

  6. запись не добавляется;

  7. ошибки выводятся в #formErrors;
  8. в #message можно вывести краткое сообщение “Исправьте ошибки формы”.

3.4. Добавление записи через форму

При успешной валидации:

  1. Формируется новый объект записи (нормализация + преобразование типов).
  2. Назначается новый id (например, maxId + 1).
  3. Запись добавляется в items.
  4. Обновляется интерфейс renderList(items).
  5. Форма очищается (form.reset() или ручная очистка полей).
  6. Сообщение об успехе выводится в #message.

3.5. Асинхронная интеграция с внешним сервисом

Необходимо реализовать один из вариантов интеграции (любой один, но полностью):

Вариант A (рекомендуемый): загрузка внешних записей и добавление в список. Сценарий:

  1. Кнопка “Загрузить данные” запускает async функцию.
  2. Выполняется fetch(...), получаем JSON.
  3. Данные преобразуются в формат ваших записей (минимум title/value/status/createdAt).
  4. Добавляются в items (например, 3–5 записей).
  5. UI обновляется renderList(items).
  6. При ошибке:

  7. UI не падает;

  8. в #message выводится ошибка (человеко-понятная);
  9. подробности можно выводить в консоль.

Вариант B: загрузка справочника статусов (массив строк) и обновление <select> в форме. Сценарий:

  1. fetch получает массив статусов.
  2. select пересобирается через DOM.
  3. Выводится сообщение об успехе/ошибке.

Вариант C: обогащение данных записи (например, подгрузка “доп. инфо” по id). Сценарий:

  1. Пользователь нажимает “Обновить” на карточке.
  2. По id делается fetch, возвращается JSON.
  3. Запись обновляется в массиве, затем renderList(...).

3.6. Обязательные сценарии итоговой задачи

Студент обязан продемонстрировать:

  1. Все сценарии ЛР3 (показ всех, фильтр new, сортировка по value ↓, статистика, кнопка удаления с dataset).
  2. Наличие формы добавления записи.
  3. Валидацию формы с использованием регулярных выражений (минимум 2 правила на RegExp).
  4. Добавление записи в массив items только при успешной валидации.
  5. Асинхронный сценарий fetch/async/await с обработкой JSON и контролем ошибок (без падения интерфейса).

3.7. Требования к сдаче

В одном репозитории должны быть:

  • обновлённый index.html (форма, #formErrors, кнопка интеграции, #list, #message);
  • data.js (массив объектов);
  • logic.js (валидация, нормализация, функции обработки данных);
  • script.js (DOM + события + renderList + управление формой);
  • (при необходимости) api.js (сетевой слой);
  • уточнение в README.md (что добавлено в ЛР4: форма, валидация, fetch);
  • passport.md остаётся и используется дальше.

3.8. Запрет

Запрещается использование систем искусственного интеллекта для выполнения лабораторной работы.

Работы, выполненные с использованием ИИ, полностью или частично скопированные, а также не сданные, оцениваются в 0 баллов без возможности доработки.


4. Контрольные вопросы

  1. Что такое регулярные выражения и в каких задачах они применяются в web-разработке?
  2. Чем отличается re.test(str) от str.match(re)?
  3. Зачем нужны якоря ^ и $ при валидации формата?
  4. Почему проверка RegExp не всегда гарантирует корректность значения (пример: дата)?
  5. Что такое нормализация ввода и зачем она нужна (пример с пробелами)?
  6. Как работает событие submit формы и зачем нужен preventDefault()?
  7. В чём разница между синхронным и асинхронным кодом в JavaScript?
  8. Что возвращает fetch и почему без await нельзя сразу получить данные?
  9. Как правильно обработать ошибки сети и HTTP-статусы при запросе?
  10. Почему валидацию и сетевые запросы нужно выносить в функции и модули, а не писать внутри обработчиков?

5. Чек-лист для самопроверки

Баллы Критерии оценки
20 Выполнены задания на закрепление теории (блок 2.1: по 2 задачи на каждый блок A–F, результаты выведены в консоль, ошибок нет); в проекте реализованы форма и блок ошибок (#formErrors), введена валидация с использованием регулярных выражений (минимум 2 правила RegExp) и смысловых проверок; добавление записи происходит только при успешной валидации; реализован асинхронный сценарий fetch через async/await с обработкой JSON и контролем ошибок (ошибки не ломают UI, сообщение выводится в #message); сохранена архитектура (data.js, logic.js, script.js, при необходимости api.js), нет дублирования логики в обработчиках; сохранены и работают все сценарии ЛР3 (показ всех, фильтр new, сортировка, статистика, удаление через dataset); изменения зафиксированы в GitHub (коммиты и актуальные файлы).
16–19 Теоретический блок 2.1 выполнен почти полностью (допущены 1–2 недочёта: не выведен результат одной задачи, есть незначительная ошибка), и/или валидация реализована частично (например, только формат без смысловой проверки), и/или асинхронность работает, но обработка ошибок неполная (например, не проверяется resp.ok), при этом проект не падает, архитектура в целом соблюдена и ключевые сценарии ЛР3 сохранены.
12–15 Теоретический блок 2.1 выполнен частично (не все блоки A–F), и/или форма есть, но валидация слабая (ошибки не показываются или правила RegExp формальны), и/или асинхронный сценарий есть, но результаты не интегрируются в проект (только вывод в консоль), и/или нарушена модульность (валидация/RegExp/сетевой код в обработчиках), при этом часть сценариев ЛР3 может быть реализована не полностью.
8–11 Форма присутствует, но добавление записи нестабильно (нет устойчивой валидации, возможны NaN/пустые поля), регулярные выражения используются формально или отсутствуют, fetch/async не демонстрируется или приводит к ошибкам, сообщения пользователю неструктурированы, модульность нарушена, интерфейс может работать фрагментарно.
1–7 Формальный шаблон без рабочей логики: отсутствует теоретический блок 2.1, нет корректной валидации, нет RegExp, нет асинхронной интеграции, интерфейс ломается при ошибках, модульность отсутствует, базовые сценарии ЛР3 не сохранены.
0 Работа не сдана / неработоспособна / выполнена с использованием ИИ.

6. Шаблон отчёта

👉 Скачать шаблон отчёта