<!DOCTYPE html>
<html class="h-100" data-bs-theme="light" data-mantine-color-scheme="light" lang="ru" prefix="og: https://ogp.me/ns#">
<head>
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<link crossorigin="true" href="https://cdn.hexlet.io" rel="preconnect">
<link href="https://mc.yandex.ru" rel="preconnect">
<meta content="aa2vrdtq64dub8knuf83lwywit311w" name="facebook-domain-verification">
<link href="/favicon.ico" rel="icon" sizes="any">
<link href="/favicon.svg" rel="icon" type="image/svg+xml">
<link href="/apple-touch-icon.png" rel="apple-touch-icon">
<link href="/manifest.webmanifest" rel="manifest">
<script>
//<![CDATA[
window.gon={};gon.ym_counter="25559621";gon.is_bot=true;gon.applications={};gon.current_user={"id":null,"last_viewed_notification_id":null,"email":null,"state":null,"first_name":"","last_name":"","created_at":"2026-02-26 18:34:14 UTC","current_program":null,"current_team":null,"full_name":"","guest":true,"can_use_paid_features":false,"is_hexlet_employee":false,"sanitized_phone_number":"","can_subscribe":true,"can_renew_education":false};gon.token="H2E6DVgEEfEw3X0rOc8afC0AoWnEEcI9Z8ApvJly6MbwsPE6qnq8kYaeWbM1wOoL7QmMw8wmPJ_aILPoy3UPqA";gon.locale="ru";gon.language="ru";gon.theme="light";gon.rails_env="production";gon.mobile=false;gon.google={"analytics_key":"UA-1360700-51","optimize_key":"GTM-5QDVFPF"};gon.captcha={"google_v3_site_key":"6LenGbgZAAAAAM7HbrDbn5JlizCSzPcS767c9vaY","yandex_site_key":"ysc1_Vyob5ZPPUdPBsu0ykt8bVFdzsfpoVjQChLGl2b4g19647a89","verification_failed":null};gon.social_signin=false;gon.typoreporter_google_form_id="1FAIpQLSeibfGq-KvWQ2Fyru-zkFFRVTLBuzXAHAoEyN1p49FtDmNoNA";
//]]>
</script>
<meta charset="utf-8">
<title>GET-запрос | JS: Синхронная асинхронность</title>
<meta name="description" content="GET-запрос / JS: Синхронная асинхронность: Учимся работать с запросом GET и обрабатывать ошибки">
<link rel="canonical" href="https://ru.hexlet.io/courses/js-sync/lessons/request-get/theory_unit">
<meta name="robots" content="noarchive">
<meta property="og:title" content="GET-запрос">
<meta property="og:title" content="JS: Синхронная асинхронность">
<meta property="og:description" content="GET-запрос / JS: Синхронная асинхронность: Учимся работать с запросом GET и обрабатывать ошибки">
<meta property="og:url" content="https://ru.hexlet.io/courses/js-sync/lessons/request-get/theory_unit">
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="sEbDb2-7wThLZYHQc8HOP7tEj2hjguZbOGQmXa4jUZBflwhYncVsWP0mpUh_zj5Ie02iwmu1GPmFhLwJ_CS2_g" />
<script src="/vite/assets/inertia-DfXos102.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/preload-helper-BJ4cLWpC.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/init-BrRXra1y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ahoy-DrlRQ-1D.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/analytics-cb8xch9l.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ErrorFallbackBlock-naDSYSy9.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Surface-DL2bpZA-.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/gon-D3e4yh1x.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/mantine-CGMYrt2Y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/utils-DRqSHbQE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/extends-C-EagtpE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/inheritsLoose-BBd-DCVI.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/objectWithoutPropertiesLoose-DRHXDhjp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/index.esm-DAqKOkZ0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Button-CGPUux8l.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/CloseButton-D1euiPao.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Group-BX48WcuU.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Loader-BQEY8g6v.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Modal-Cy3HByv7.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/OptionalPortal-1Hza5P2w.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Stack-CtjJzfw4.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Textarea-Ck64llAy.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Box-B5-OOzBf.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/DirectionProvider-Dc9zdUke.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/events-DJQOhap0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-reduced-motion-D2owz4wa.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-disclosure-zKtK5W1r.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-hotkeys-Cnc_Rwkb.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/random-id-DOQyszCZ.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/notifications.store-C-3AFSMn.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/exports-C_MrNx_T.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/axios-BEvgo0ym.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dayjs.min-BkKovM-s.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/i18next-BlSq9s7B.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/client-U9M77rxp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-dom-DaLxUz_h.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useTranslation-Bx1Cdrkz.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/compiler-runtime-6XxiPFnt.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/jsx-runtime-CwjcCKJi.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-CkL4ZRHB.js" as="script" crossorigin="anonymous">
<link rel="stylesheet" href="/vite/assets/application-BqhCP46M.js" />
<script src="/vite/assets/application-Df9RExpe.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/autocomplete-VMNbxKGl.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/createPopper-C3aM9r1M.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/js.cookie-D1-O8zkX.js" as="script" crossorigin="anonymous"><link rel="stylesheet" href="/vite/assets/application-C8HjmMaq.css" media="screen" />
<script>
window.ym = function(){(ym.a=ym.a||[]).push(arguments)};
window.addEventListener('load', function() {
setTimeout(function() {
ym.l = 1*new Date();
ym(window.gon.ym_counter, "init", {
clickmap: true,
trackLinks: true,
accurateTrackBounce: true,
webvisor: true
});
// Загружаем скрипт
var k = document.createElement('script');
k.async = 1;
k.src = 'https://mc.yandex.ru/metrika/tag.js';
document.head.appendChild(k);
ym(window.gon.ym_counter, 'getClientID', function(clientID) {
window.ymClientId = clientID;
});
}, 1500);
});
</script>
<!-- Google Tag Manager - deferred -->
<script>
// dataLayer stub сразу — пуши работают до загрузки скрипта
window.dataLayer = window.dataLayer || [];
// Сам скрипт — отложенно после load
window.addEventListener('load', function() {
setTimeout(function() {
dataLayer.push({'gtm.start': new Date().getTime(), event: 'gtm.js'});
var j = document.createElement('script');
j.async = true;
j.src = 'https://www.googletagmanager.com/gtm.js?id=GTM-WK88TH';
document.head.appendChild(j);
}, 1500);
});
</script>
<!-- End Google Tag Manager -->
</head>
<body>
<noscript>
<div>
<img alt="" src="https://mc.yandex.ru/watch/25559621" style="position:absolute; left:-9999px;">
</div>
</noscript>
<header class="sticky-top bg-body">
<nav class="navbar navbar-expand-lg">
<div class="container-xxl">
<a class="navbar-brand" href="/"><img alt="Логотип Хекслета" height="24" src="https://ru.hexlet.io/vite/assets/logo_ru_light-BpiEA1LT.svg" width="96">
</a><button aria-controls="collapsable" aria-expanded="false" aria-label="Меню" class="navbar-toggler border-0 mb-0 mt-1" data-bs-target="#collapsable" data-bs-toggle="collapse">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="collapsable">
<ul class="navbar-nav mb-lg-0 mt-lg-1">
<li class="nav-item dropdown">
<button aria-haspopup class="btn nav-link" data-bs-toggle="dropdown" type="button">
Все курсы
<span class="bi bi-chevron-down align-middle ms-1"></span>
</button>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item d-flex py-2" href="/courses"><div class="fw-bold me-auto">Все что есть</div>
<div class="text-muted">117</div>
</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-item">
<b>Популярные категории</b>
</li>
<li>
<a class="dropdown-item py-2" href="/courses_devops">Курсы по DevOps
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_data_analytics">Курсы по аналитике данных
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_programming">Курсы по программированию
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_testing">Курсы по тестированию
</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-item">
<b>Популярные курсы</b>
</li>
<li>
<a class="dropdown-item py-2" href="/programs/devops-engineer-from-scratch">DevOps-инженер с нуля
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/go">Go-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/java">Java-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/python">Python-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/qa-auto-engineer-java">Автоматизатор тестирования на Java
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/data-analytics">Аналитик данных
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/frontend">Фронтенд-разработчик
</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<button aria-haspopup class="btn nav-link" data-bs-toggle="dropdown" type="button">
О Хекслете
<span class="bi bi-chevron-down align-middle"></span>
</button>
<ul class="dropdown-menu bg-body">
<li>
<a class="dropdown-item py-2" href="/pages/about">О нас
</a></li>
<li>
<a class="dropdown-item py-2" href="/blog">Блог
</a></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/hse-research" role="button">Результаты (Исследование)
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://career.hexlet.io" role="button">Хекслет Карьера
</span></li>
<li>
<a class="dropdown-item py-2" href="/testimonials">Отзывы студентов
</a></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://t.me/hexlet_help_bot" role="button">Поддержка (В ТГ)
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/referal-program/?promo_creative=priglasite-druzei&promo_name=referal-program&promo_position=promo_position&promo_start=010724&promo_type=link" role="button">Реферальная программа
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/certificate" role="button">Подарочные сертификаты
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://hh.ru/employer/4307094" role="button">Вакансии
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://b2b.hexlet.io" data-target="_blank" role="button">Компаниям
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://hexly.ru/" data-target="_blank" role="button">Колледж
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://hexlyschool.ru/" data-target="_blank" role="button">Частная школа
</span></li>
</ul>
</li>
<li><a class="nav-link" href="/subscription/new">Подписка</a></li>
</ul>
<ul class="navbar-nav flex-lg-row align-items-lg-center gap-2 ms-auto">
<li>
<a class="nav-link" aria-label="Переключить тему" href="/theme/switch?new_theme=dark"><span aria-hidden="true" class="bi bi-moon"></span>
</a></li>
<li>
<span data-target="_self" class="nav-link external-link" data-href="/u/new" role="button"><span>Регистрация</span>
</span></li>
<li>
<span data-target="_self" class="nav-link external-link" data-href="https://ru.hexlet.io/session/new" role="button"><span>Вход</span>
</span></li>
</ul>
</div>
</div>
</nav>
</header>
<div class="x-container-xxxl">
</div>
<main class="mb-6 min-vh-100 h-100">
<div id="app" data-page="{"component":"web/courses/lessons/theory_unit","props":{"errors":{},"locale":"ru","language":"ru","httpsHost":"https://ru.hexlet.io","host":"ru.hexlet.io","colorScheme":"light","auth":{"user":{"id":null,"last_viewed_notification_id":null,"email":null,"state":null,"first_name":"","last_name":"","created_at":"2026-02-26T18:34:14.559Z","current_program":null,"current_team":null,"full_name":"","guest":true,"can_use_paid_features":false,"is_hexlet_employee":false,"sanitized_phone_number":"","can_subscribe":true,"can_renew_education":false}},"cloudflareTurnstileSiteKey":"0x4AAAAAAA15KmeFXzd2H0Xo","vkIdClientId":"51586979","yandexIdClientId":"88d071f1d3384eb4bd1deb37910235c7","formAuthToken":"ykrUaORYputkxnbfJX994AebnRqxgGOJeri_fx5GpRklmx9fFiYLi9KFUkcpcI2Xx5KwsLm3nSvHWCUrTEFCdw","topics":[{"id":16870,"title":"Учитель, у меня проблема странная какая-то. Не срабатывает 5-ый тест, а в `output` пишет вывод для 4-го. \n\n```\nRequest › set 5\n\n expect(received).toBe(expected) // Object.is equality\n \n Expected: \"http://localhost:8080/operators\"\n Received: undefined\n \n Difference:\n \n Comparing two different types of values. Expected string but received undefined.\n\n 33 | const title = 'Операции';\n 34 | solution(title, link, (err, result) => {\n > 35 | expect(result).toBe(`${link}/operators`);\n | ^\n 36 | done(err);\n 37 | });\n 38 | });\n```\nНо выше это вывод для 4-го и он сработал \n```\nRequest\n ✓ set 1 (54ms)\n ✓ set 2 (24ms)\n ✓ set 3 (16ms)\n ✓ set 4 (12ms)\n ✕ set 5 (26ms)\n```\n\n\nМой код\n\n`// removed`\n\nВот этот `callback` для ошибки, с ним у меня что-то не то или он не там стоит.","plain_title":"Учитель, у меня проблема странная какая-то. Не срабатывает 5-ый тест, а в output пишет вывод для 4-го. Request › set 5 expect(received).toBe(expected) // Object.is equality Expected: \"http://localhost:8080/operators\" Received: undefined Difference: Comparing two different types of values. Expected string but received undefined. 33 | const title = 'Операции'; 34 | solution(title, link, (err, result) => { > 35 | expect(result).toBe(`${link}/operators`); | ^ 36 | done(err); 37 | }); 38 | }); Но выше это вывод для 4-го и он сработал Request ✓ set 1 (54ms) ✓ set 2 (24ms) ✓ set 3 (16ms) ✓ set 4 (12ms) ✕ set 5 (26ms) Мой код // removed Вот этот callback для ошибки, с ним у меня что-то не то или он не там стоит. ","creator":{"public_name":"Константин Бочинин","id":43218,"is_tutor":false},"comments":[{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":35882,"body":"Но у тебя ведь не во всех ифах стоит console.log. Например совершенно непонятно что будет тут `searchedLinks.has(currLinks[0])` если currLinks будет пустым массивом.","topic_id":16870},{"creator":{"public_name":"Константин Бочинин","id":43218,"is_tutor":false},"id":35804,"body":"Я немного переписал код, та ошибка ушла, но я по прежнему не могу поймать `callback` с ошибкой 5-го теста:\n\n`// removed`\n\nВ самом низу последнее условие:\n\n`// removed`\n\nтам ошибка и она должна быть поймана, но тест пишет ` Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.`","topic_id":16870},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":35778,"body":"Вопрос в том как ты отлаживаешь. Покажи тот же код но утыканный консоль логами. Посмотрю правильно ли ты его используешь.","topic_id":16870}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"GET-запрос","entity_url":null,"active":true}},{"id":17090,"title":"Поиск в ширину?)","plain_title":"Поиск в ширину?) ","creator":{"public_name":"Konstantin Zemliakov","id":130883,"is_tutor":false},"comments":[{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":36212,"body":"Ну это уже как реализуете)","topic_id":17090}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"GET-запрос","entity_url":null,"active":true}},{"id":21009,"title":"не подскажете в чем может быть проблема? вроде бы я должен добраться до нужной ссылки, но на последней итерации программа вылетает \n```import url from 'url';\nimport http from 'http';\n\nconst getTitle = body => body.match(/<h1>(.*?)<\\/h1>/)[1];\nconst getLinks = body =>\n (body.match(/href=\"\\/(.*?)\">/g) || [])\n .map(item => item.match(/href=\"\\/(.*?)\">/)[1]);\n\n// BEGIN (write your solution here)\n const checked = new Set();\nconst solution = (title, address, callback) => {\n console.log(title);\n console.log(checked);\n const urlObj = url.parse(address);\n checked.add(address);\nhttp.get(address, res => {\n const body = [];\n res.on('data', chunk => {\n body.push(chunk.toString());\n}).on('end', () => {\n const html = body.join();\n const mainTitle = getTitle(html);\n console.log(mainTitle);\n const links = getLinks(html);\n if (title === mainTitle) {\n callback(null, address);\n return;\n } \n links.forEach(el => {\n if (!checked.has(urlObj.protocol + '//' + urlObj.host + '/' + el)) {\n solution(title, urlObj.protocol + '//' + urlObj.host + '/' + el, callback);\n return;\n }\n });\n return callback(null);\n });\n });\n}\nexport default solution;``` ","plain_title":"не подскажете в чем может быть проблема? вроде бы я должен добраться до нужной ссылки, но на последней итерации программа вылетает ```import url from 'url'; import http from 'http'; const getTitle = body => body.match(/(.?)<\\/h1>/)[1]; const getLinks = body => (body.match(/href=\"\\/(.?)\">/g) || []) .map(item => item.match(/href=\"\\/(.*?)\">/)[1]); // BEGIN (write your solution here) const checked = new Set(); const solution = (title, address, callback) => { console.log(title); console.log(checked); const urlObj = url.parse(address); checked.add(address); http.get(address, res => { const body = []; res.on('data', chunk => { body.push(chunk.toString()); }).on('end', () => { const html = body.join(); const mainTitle = getTitle(html); console.log(mainTitle); const links = getLinks(html); if (title === mainTitle) { callback(null, address); return; } links.forEach(el => { if (!checked.has(urlObj.protocol + '//' + urlObj.host + '/' + el)) { solution(title, urlObj.protocol + '//' + urlObj.host + '/' + el, callback); return; } }); return callback(null); }); }); } export default solution;``` ","creator":{"public_name":"Alexandr Vasilev","id":184524,"is_tutor":false},"comments":[{"creator":{"public_name":"Alexandr Vasilev","id":184524,"is_tutor":false},"id":44688,"body":"/usr/lib/node_modules/jest-cli/node_modules/expect/build/index.js:306\n throw error;","topic_id":21009},{"creator":{"public_name":"Alexandr Vasilev","id":184524,"is_tutor":false},"id":45014,"body":"```\n FAIL __tests__/solution.test.js\n Request\n ✓ set 1 (2689ms)\n ✕ set 2 (47ms)\n ✕ set 3 (17ms)\n ✕ set 4 (31ms)\n ✕ set 5 (6ms)\n\n ● Request › set 2\n\n expect(received).toBe(expected) // Object.is equality\n\n Expected: \"http://localhost:8080/statements\"\n Received: undefined\n\n Difference:\n\n Comparing two different types of values. Expected string but received undefined.\n\n 15 | const title = 'Инструкции';\n 16 | solution(title, link, (err, result) => {\n > 17 | expect(result).toBe(`${link}/statements`);\n | ^\n 18 | done(err);\n 19 | });\n 20 | });\n\n at toBe (__tests__/solution.test.js:17:22)\n at IncomingMessage.callback (solution.js:35:10)\n\n ● Request › set 3\n\n expect(received).toBe(expected) // Object.is equality\n\n Expected: \"http://localhost:8080/statements\"\n Received: undefined\n\n Difference:\n\n Comparing two different types of values. Expected string but received undefined.\n\n 15 | const title = 'Инструкции';\n 16 | solution(title, link, (err, result) => {\n > 17 | expect(result).toBe(`${link}/statements`);\n | ^\n 18 | done(err);\n 19 | });\n 20 | });\n\n at toBe (__tests__/solution.test.js:17:22)\n at IncomingMessage.callback (solution.js:35:10)\n\n ● Request › set 4\n\n expect(received).toBe(expected) // Object.is equality\n\n Expected: \"http://localhost:8080/statements\"\n Received: undefined\n\n Difference:\n\n Comparing two different types of values. Expected string but received undefined.\n\n 15 | const title = 'Инструкции';\n 16 | solution(title, link, (err, result) => {\n > 17 | expect(result).toBe(`${link}/statements`);\n | ^\n 18 | done(err);\n 19 | });\n 20 | });\n\n at toBe (__tests__/solution.test.js:17:22)\n at IncomingMessage.callback (solution.js:35:10)\n\n ● Request › set 5\n\n expect(received).toBe(expected) // Object.is equality\n\n Expected: \"http://localhost:8080/expressions\"\n Received: undefined\n\n Difference:\n\n Comparing two different types of values. Expected string but received undefined.\n\n 24 | const title = 'Выражения';\n 25 | solution(title, link, (err, result) => {\n > 26 | expect(result).toBe(`${link}/expressions`);\n | ^\n 27 | done(err);\n 28 | });\n 29 | });\n\n at toBe (__tests__/solution.test.js:26:22)\n at IncomingMessage.callback (solution.js:35:10)\n\nTest Suites: 1 failed, 1 total\nTests: 4 failed, 1 passed, 5 total\nSnapshots: 0 total\nTime: 4.029s\nRan all test suites.\n console.log solution.js:23\n Википедия\n\n/usr/lib/node_modules/jest-cli/node_modules/expect/build/index.js:306\n throw error;\n ^\n\nError: expect(received).toBe(expected) // Object.is equality\n\nExpected: \"http://localhost:8080/operators\"\nReceived: undefined\n\nDifference:\n\n Comparing two different types of values. Expected string but received undefined.\n at /usr/src/app/__tests__/solution.test.js:36:22\n at IncomingMessage.res.on.on (/usr/src/app/solution.js:50:14)\n at IncomingMessage.emit (events.js:187:15)\n at endReadableNT (_stream_readable.js:1085:12)\n at process._tickCallback (internal/process/next_tick.js:63:19)\nMakefile:2: recipe for target 'test' failed\nmake: *** [test] Error 1\nmake: Leaving directory '/usr/src/app'\nstatus: finished → Check your code. Tests fai\n```","topic_id":21009},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":45025,"body":"Отлично, давайте попробуем проанализировать, что вам хотят тут сказать?\n\n```\n Expected: \"http://localhost:8080/statements\"\n Received: undefined\n```\n\n","topic_id":21009},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":44768,"body":"Хм, вы хотите сказать что вот ровно одну строчку вывело?","topic_id":21009},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":44549,"body":"А ошибка какая?","topic_id":21009}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"GET-запрос","entity_url":null,"active":true}},{"id":8423,"title":"Из за чего возникает такая ошибка?\n```\n/usr/src/app/solution.js:4\nconst getTitle = body => body.match(/<h1>(.*?)<\\/h1>/)[1];\n ^\n\nTypeError: Cannot read property '1' of null\n```\n?\n\nПохоже на то что в body этого нет...","plain_title":"Из за чего возникает такая ошибка? ``` /usr/src/app/solution.js:4 const getTitle = body => body.match(/(.*?)<\\/h1>/)[1]; ^ TypeError: Cannot read property '1' of null ``` ? Похоже на то что в body этого нет... ","creator":{"public_name":"Николай Артамонов","id":6107,"is_tutor":false},"comments":[{"creator":{"public_name":"Николай Артамонов","id":6107,"is_tutor":false},"id":16463,"body":"Это понятно, как отловить то что я получаю в body которое приводит к такому результату? сonsole.log не помогает - ошибка показывается раньше","topic_id":8423},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":16461,"body":"`match` возвращает `null`, а ты применяешь к нему `[1]`","topic_id":8423},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":16464,"body":"так тут же все ясно, ты матчишь то чего нет.","topic_id":8423},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":16485,"body":"Например так, да)","topic_id":8423},{"creator":{"public_name":"Николай Артамонов","id":6107,"is_tutor":false},"id":16467,"body":"Мм, null возвращает match, значит мне нужно сначала как то проверить есть ли заголовок на странице ?\n","topic_id":8423},{"creator":{"public_name":"Николай Артамонов","id":6107,"is_tutor":false},"id":16572,"body":"Оказалось, что я ошибочно предполагал что переход по такой цепочке home -> Выражения -> Инструкции соберется в такой адрес home/Выражения/Инструкции,\nа в веб версии заметил что получается типа home/Инструкции","topic_id":8423}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"GET-запрос","entity_url":null,"active":true}},{"id":50696,"title":"Что за дела, тесты вроде все прошли, но в конце все равно какая-то ошибка?\n\n```\nPASS __tests__/solution.test.js\n\n Request\n ✓ set 1 (21 ms)\n ✓ set 2 (24 ms)\n ✓ set 3 (27 ms)\n ✓ set 4 (13 ms)\n ✓ set 5 (24 ms)\n\n\nTest Suites: 1 passed, 1 total\nTests: 5 passed, 5 total\nSnapshots: 0 total\nTime: 0.953 s, estimated 1 s\nRan all test suites.\n\nevents.js:292\n throw er; // Unhandled 'error' event\n ^\n\nError: connect ECONNREFUSED 127.0.0.1:80\n at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1146:16)\nEmitted 'error' event on ClientRequest instance at:\n at Socket.socketErrorListener (_http_client.js:469:9)\n at Socket.emit (events.js:315:20)\n at emitErrorNT (internal/streams/destroy.js:106:8)\n at emitErrorCloseNT (internal/streams/destroy.js:74:3)\n at processTicksAndRejections (internal/process/task_queues.js:80:21) {\n errno: -111,\n code: 'ECONNREFUSED',\n syscall: 'connect',\n address: '127.0.0.1',\n port: 80\n}\n\nmake: *** [Makefile:2: test] Error 1\n\nmake: Leaving directory '/usr/src/app'\n\nstatus: finished → Тесты завершились с ошибками. Изучите их вывод. Вдохните. Выдохните. Исправьте код.\n\n```\n\nссылка на ревью\nhttps://ru.hexlet.io/code_reviews/355885?submission_id=451349#\n\n","plain_title":"Что за дела тесты вроде все прошли, но в конце все равно какая-то ошибка? PASS __tests__/solution.test.js Request ✓ set 1 (21 ms) ✓ set 2 (24 ms) ✓ set 3 (27 ms) ✓ set 4 (13 ms) ✓ set 5 (24 ms) Test Suites: 1 passed, 1 total Tests: 5 passed, 5 total Snapshots: 0 total Time: 0.953 s, estimated 1 s Ran all test suites. events.js:292 throw er; // Unhandled 'error' event ^ Error: connect ECONNREFUSED 127.0.0.1:80 at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1146:16) Emitted 'error' event on ClientRequest instance at: at Socket.socketErrorListener (_http_client.js:469:9) at Socket.emit (events.js:315:20) at emitErrorNT (internal/streams/destroy.js:106:8) at emitErrorCloseNT (internal/streams/destroy.js:74:3) at processTicksAndRejections (internal/process/task_queues.js:80:21) { errno: -111, code: 'ECONNREFUSED', syscall: 'connect', address: '127.0.0.1', port: 80 } make: *** [Makefile:2: test] Error 1 make: Leaving directory '/usr/src/app' status: finished → Тесты завершились с ошибками. Изучите их вывод. Вдохните. Выдохните. Исправьте код. ссылка на ревью https://ru.hexlet.io/codereviews/355885?submissionid=451349# ","creator":{"public_name":"Yuriy Semenyuk","id":310124,"is_tutor":false},"comments":[{"creator":{"public_name":"Михаил Деркач","id":58899,"is_tutor":false},"id":108498,"body":"Приветствую\n\nА интерфейс позволяет проходить дальше по шагам? Выглядит как ошибка соединения не связанная с самим кодом","topic_id":50696},{"creator":{"public_name":"Михаил Деркач","id":58899,"is_tutor":false},"id":108590,"body":"В случае вызова `callback` в одном из случаев выполнение дальнейшего кода продолжается из-за чего и возникает ошибка\n","topic_id":50696},{"creator":{"public_name":"Yuriy Semenyuk","id":310124,"is_tutor":false},"id":108586,"body":"не, не позволяет, кнопка завершить не активна.\nу меня предыдущее решение прошло, я решил переделать потом, после того как решение учителя посмотрел, вроде так лучше, но что-то не идет )","topic_id":50696}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"GET-запрос","entity_url":null,"active":true}},{"id":15111,"title":"по какой причине не проходит проверку первый тест?\n```\n// removed\n```","plain_title":"по какой причине не проходит проверку первый тест? // removed ","creator":{"public_name":"TopProgrammist InTheWorld","id":151755,"is_tutor":false},"comments":[{"creator":{"public_name":"TopProgrammist InTheWorld","id":151755,"is_tutor":false},"id":31722,"body":"```\nmake: Entering directory '/usr/src/app'\nnpm test -s\n console.log solution.js:20\n http://localhost:8080/\n\nMakefile:2: recipe for target 'test' failed\nmake: *** [test] Terminated\nstatus: finished → Code has been running for too long. Infinite loop or recursion. Check terminating conditions.\n```\nкак-то так, вывода собственно нет. я вызываю колбек с \"правильным\" результатом, печатаю его даже, а тесты не проходит","topic_id":15111},{"creator":{"public_name":"TopProgrammist InTheWorld","id":151755,"is_tutor":false},"id":31825,"body":"этот код просто возвращал колбек с результатом (адресом), которое по-моему и ожидает тест","topic_id":15111},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":31715,"body":"Понятия не имею), я ж не вижу вывода тестов.","topic_id":15111},{"creator":{"public_name":"TopProgrammist InTheWorld","id":151755,"is_tutor":false},"id":31832,"body":"я решил выполнять задание частями, выполняя по одному условию. потому что перестал понимать что вообще происходит(\n\nв разных заданиях по разному. где-то у вас можно по одному проходить условия задачи, где-то нет. видимо, в этом задании по одному нельзя выполнять тесты","topic_id":15111},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":31826,"body":"ОЖидает да, но прочитай еще раз внимательно задание. Там разве сказано что надо выполнить один запрос и ты сразу получишь результат?","topic_id":15111},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":31839,"body":"Достаточно сделать две вещи:\n\n1. Открыть веб доступ и побродить по ссылкам.\n1. Открыть тесты и сопоставить их с тем что видно в веб доступе.","topic_id":15111},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":31821,"body":"> Code has been running for too long\n\nНу и по коду видно что он вообще не решает задачу. Здесь нет сбора ссылок со страницы и рекурсивного обхода.","topic_id":15111}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"GET-запрос","entity_url":null,"active":true}},{"id":20893,"title":"https://ru.hexlet.io/code_reviews/72496\nУ меня вопросы:\n1) forEach в итоге-то синхронная функция? Тогда я что-то не понимаю как с помощью неё получается асинхронность по способу приведенным в прошлом курсе. Сделал аналогично, но вот если forEach синхронная, то как это обеспечивает асинхронность при её использовании?\n2) Объясните пожалуйста где и чем в решении учителя обеспечивается асинхронность?\n","plain_title":"https://ru.hexlet.io/code_reviews/72496 У меня вопросы: 1) forEach в итоге-то синхронная функция? Тогда я что-то не понимаю как с помощью неё получается асинхронность по способу приведенным в прошлом курсе. Сделал аналогично, но вот если forEach синхронная, то как это обеспечивает асинхронность при её использовании? 2) Объясните пожалуйста где и чем в решении учителя обеспечивается асинхронность? ","creator":{"public_name":"Bator Zhigzhitov","id":186940,"is_tutor":false},"comments":[{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":44202,"body":"Асинхронным является выполнение http запроса. То есть forEach выполняется до того как выполнятся http запросы, делающиеся внутри `iter`.","topic_id":20893},{"creator":{"public_name":"Bator Zhigzhitov","id":186940,"is_tutor":false},"id":44257,"body":"А в этой теме где асинхронность тогда? https://ru.hexlet.io/courses/js_async/lessons/each/theory_unit","topic_id":20893},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":44291,"body":"Асинхронность там появляется в тот момент, когда туда передаюются асинхронные функции. Каждая из которых запускается независимо.","topic_id":20893}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"GET-запрос","entity_url":null,"active":true}},{"id":18000,"title":"Пробую использовать поиск код из книги \"Грокаем алгоритмы\", глава про поиск в ширину. А в нём цикл while. Так лучше не делать или сойдёт?\nВот что сделал:\n\n`// removed`","plain_title":"Пробую использовать поиск код из книги \"Грокаем алгоритмы\", глава про поиск в ширину. А в нём цикл while. Так лучше не делать или сойдёт? Вот что сделал: // removed ","creator":{"public_name":"Алексей Ильин","id":148143,"is_tutor":false},"comments":[{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":38039,"body":"А какую ошибку показывают тесты?","topic_id":18000},{"creator":{"public_name":"Kirill Kikimov","id":79345,"is_tutor":false},"id":38649,"body":"Почитал комменты, действительно, поиск в ширину сильно усложняет. Пока не придумал как поймать тот момент что все обработчики завершились без вызова коллбека, вижу решение в лоб, по таймеру вызывать функцию проверяющую вызов коллбека и фактически по таймауту завершаться с ошибкой, но это не так красиво. Кажется можно сделать что то похожее на ватерфол из предыдущего курса...","topic_id":18000},{"creator":{"public_name":"Алексей Ильин","id":148143,"is_tutor":false},"id":38038,"body":"Нет, решение не работает. Код-ревью нет соответственно.","topic_id":18000},{"creator":{"public_name":"Алексей Ильин","id":148143,"is_tutor":false},"id":38324,"body":"Ага. Плюс программирования конечно что можно всё взять и попробовать, только иногда про это забываю. Решение учителя как часто бывает простое и логичное. Я там такое начал городить. )","topic_id":18000},{"creator":{"public_name":"Алексей Ильин","id":148143,"is_tutor":false},"id":38651,"body":"Посмотри как я сделал.","topic_id":18000},{"creator":{"public_name":"Алексей Ильин","id":148143,"is_tutor":false},"id":38149,"body":"Чудом решил. Посмотрите, пожалуйста, на сколько корректное решение [получилось](https://ru.hexlet.io/code_reviews/60816?submission_id=83541).","topic_id":18000},{"creator":{"public_name":"Алексей Ильин","id":148143,"is_tutor":false},"id":38146,"body":"Наверно про это место говорите: Expected: \"http://localhost:8080/expressions\"\nReceived: null","topic_id":18000},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":38026,"body":"Это рабочее решение? Вы можете выложить ссылку на код ревью?","topic_id":18000},{"creator":{"public_name":"Алексей Ильин","id":148143,"is_tutor":false},"id":38078,"body":"Может они говорят что результат работы функции ошибка.","topic_id":18000},{"creator":{"public_name":"Алексей Ильин","id":148143,"is_tutor":false},"id":38080,"body":"И ещё похоже коллбек функции по умолчанию несколько раз вызывается.","topic_id":18000},{"creator":{"public_name":"Алексей Ильин","id":148143,"is_tutor":false},"id":38284,"body":"Я правильно понимаю что в решении учителя все ссылки обрабатываются последовательно, а у меня параллельно?","topic_id":18000},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":38320,"body":"Ага, попробовал?)","topic_id":18000},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":38286,"body":"Как можно проверить это?","topic_id":18000},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":38144,"body":"Тут важно чтобы вы понимали как используется ваша функция и как она должна обрабатывать входные параметры. В том тесте в выводе прямо видно что от вашей функции ожидается некоторый возврат, но она его не отдает.","topic_id":18000},{"creator":{"public_name":"Алексей Ильин","id":148143,"is_tutor":false},"id":38040,"body":"FAIL __tests__/solution.test.js\n Request\n ✕ set 3 (1591ms)\n\n ● Request › set 3\n\n expect(received).toBe(expected) // Object.is equality\n\n Expected: \"http://localhost:8080/expressions\"\n Received: null\n\n Difference:\n\n Comparing two different types of values. Expected string but received null.\n\n 24 | const title = 'Выражения';\n 25 | solution(title, link, (err, result) => {\n > 26 | expect(result).toBe(`${link}/expressions`);\n | ^\n 27 | done(err);\n 28 | });\n 29 | });\n\n at __tests__/solution.test.js:26:22\n at IncomingMessage.res.on.on (solution.js:46:9)\n\nTest Suites: 1 failed, 1 total\nTests: 1 failed, 1 total\nSnapshots: 0 total\nTime: 2.915s\nRan all test suites.\n console.log solution.js:23\n <html><head><title></title></head><body><h1>Википедия</h1><p>Как вы знаете, вики это большая база знаний обо всем на свете.\n Наш сайт это не настоящая <a href=\"https://www.wikipedia.org/\">википедия</a>,\n но кое что мы сюда добавили).</p><p>Например статью про <a href=\"/operators\">операции</a>, а так же\n <a href=\"/expressions\">выражения</a>.</p></body></html>\n\n console.log solution.js:24\n Выражения\n\n console.log solution.js:25\n Википедия\n\n console.log solution.js:32\n [ 'operators', 'expressions' ]\n\n console.log solution.js:16\n http://localhost:8080/operators\n\n console.log solution.js:23\n <html><head><title></title></head><body><h1>Операции</h1><p>Операция это функция записанная особым способом (обычно инфиксно).\n Операция всегда является частью <a href=\"/expressions\">выражения</a>.</p></body></html>\n\n console.log solution.js:24\n Выражения\n\n console.log solution.js:25\n Операции\n\n console.log solution.js:32\n [ 'expressions', 'expressions' ]\n\n console.log solution.js:16\n http://localhost:8080/expressions\n\n/usr/local/lib/node_modules/jest-cli/node_modules/expect/build/index.js:308\n throw error;\n ^\n\nError: expect(received).toBe(expected) // Object.is equality\n\nExpected: \"http://localhost:8080/expressions\"\nReceived: null\n\nDifference:\n\n Comparing two different types of values. Expected string but received null.\n at /usr/src/app/__tests__/solution.test.js:29:22\n at IncomingMessage.res.on.on (/usr/src/app/solution.js:63:9)\n at IncomingMessage.emit (events.js:187:15)\n at endReadableNT (_stream_readable.js:1081:12)\n at process._tickCallback (internal/process/next_tick.js:63:19)\nMakefile:2: recipe for target 'test' failed\nmake: Leaving directory '/usr/src/app'\nmake: *** [test] Error 1","topic_id":18000},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":38070,"body":"Гут. Давайте теперь попробуем разобраться. Что по вашему тут хотят сказать тесты?","topic_id":18000},{"creator":{"public_name":"Алексей Ильин","id":148143,"is_tutor":false},"id":38184,"body":"Поиском в ширину похоже усложнил себе задачу.","topic_id":18000},{"creator":{"public_name":"Алексей Ильин","id":148143,"is_tutor":false},"id":38293,"body":"Вывести на экран массив с ссылками и посмотреть как он будет меняться во время работы функции.","topic_id":18000}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"GET-запрос","entity_url":null,"active":true}},{"id":7026,"title":"добрый вечер подскажите что за ошибка? \n```\n/usr/local/lib/node_modules/jest/node_modules/jest-matchers/build/index.js:110\n throw error;\n```","plain_title":"добрый вечер подскажите что за ошибка? /usr/local/lib/node_modules/jest/node_modules/jest-matchers/build/index.js:110 throw error; ","creator":{"public_name":"Дмитрий Круглов","id":125440,"is_tutor":false},"comments":[{"creator":{"public_name":"Дмитрий Круглов","id":125440,"is_tutor":false},"id":12959,"body":"при реализации функции с forEach мое решение проходит все тесты кроме последнего, где проверка на то что нужный заголовок не найден, при добавлении проверки на это условие выходит такая ошибка (см выше),проверка закоментирована в приведенном ниже коде. пока не понимаю почему...\n```\nexport default (expectedTitle, link, callback) => {\n const { protocol, hostname, pathname, port } = url.parse(link);\n const search = (current, visited) => {\n const path = url.format( { protocol, hostname, pathname: current, port });\n const body = [];\n http.get(path, (res) => {\n res.on('data', chunk => body.push(chunk.toString())).\n on('end',() => {\n const html = body.join();\n if (getTitle(html) === expectedTitle) {\n callback(null, path);\n return;\n }\n const newLinks = getLinks(html).filter( el => !visited.has(el));\n visited.add(visited);\n // if(newLinks.length === 0) {\n // callback(new Error('link was not found'));\n // return;\n // }\n newLinks.forEach(el => search(el,visited));\n });\n });\n };\n\n search(pathname, new Set());\n};\n```","topic_id":7026},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":12998,"body":"У вас похожий код, но вы никак не обрабатываете ситуацию в которой были просмотрены все ссылки, но ничего не было найдено","topic_id":7026}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"GET-запрос","entity_url":null,"active":true}},{"id":12670,"title":"в решении учителя вместо `hostname` + `port` можно использовать только `host` (он содержит уже в себе и hostname и port)","plain_title":"в решении учителя вместо hostname + port можно использовать только host (он содержит уже в себе и hostname и port) ","creator":{"public_name":"Игорь Инковский","id":61651,"is_tutor":false},"comments":[{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":26462,"body":"Поправил!","topic_id":12670}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"GET-запрос","entity_url":null,"active":true}}],"lesson":{"exercise":null,"units":[{"id":1583,"name":"theory","url":"/courses/js-sync/lessons/request-get/theory_unit"},{"id":1600,"name":"quiz","url":"/courses/js-sync/lessons/request-get/quiz_unit"}],"links":[],"ordered_units":[{"id":1583,"name":"theory","url":"/courses/js-sync/lessons/request-get/theory_unit"},{"id":1600,"name":"quiz","url":"/courses/js-sync/lessons/request-get/quiz_unit"}],"id":774,"slug":"request-get","state":"approved","name":"GET-запрос","course_order":300,"goal":"Учимся работать с запросом GET и обрабатывать ошибки","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"Предположим, что мы хотим программно выполнить `get` запрос к Хекслету.\nВ `nodejs` сделать это довольно просто:\n\n```javascript\nimport http from 'http'\n\nhttp.get('http://ru.hexlet.io/my', (res) => {\n console.log(res.statusCode)\n})\n```\n\nВторым параметром передается колбек, который будет вызван после получения\nответа. Он также принимает на вход объект `response`, который содержит\nв себе параметры ответа.\n\nЭтих параметров внутри `response` очень много, и только некоторые из них\nнаиболее часто используются или могут быть нам интересны. В первую очередь\nэто следующий набор:\n\n```javascript\n// response\n{\n headers: /* ... */,\n statusCode: 301,\n statusMessage: 'Moved Permanently',\n};\n```\n\nТакже `get` позволяет передавать первым параметром не адрес, а набор\nопций, из которого будет составлен адрес. Такое бывает полезно, когда\nу нас нет готового адреса, но есть его части:\n\n```javascript\nimport http from 'http'\n\n// headers, method, port, ...\nconst options = {\n hostname: 'ru.hexlet.io',\n path: 'my',\n}\n\nhttp.get(options, (res) => {\n console.log(res.statusCode)\n})\n```\n\nОбо всех доступных опциях можно прочитать в официальной документации, а\nиз самых распространенных мы выделим следующие:\n\n* headers — объект, в котором ключ — это название заголовка\n* method — например, `GET`\n* port\n* hostname\n* path\n\n## Body\n\nВ запросе выше не хватает одной важной детали: получение тела ответа.\nТут нас поджидает небольшой сюрприз. Объект `response` не содержит внутри\nсебя тело ответа. Связано это с тем, что ответ может приходить чанками,\nи `response` дает возможность получать эти чанки сразу и независимо друг от друга.\nС одной стороны, это более гибкая возможность, которая позволяет работать с большим\nтелом, без того чтобы занимать много оперативной памяти; с другой стороны, для\nпростых запросов приходится доставать тело немного более сложным способом, чем хотелось\nбы. Но, в конечном итоге, все сводится к понятному коду, который нужно просто запомнить.\n\n```javascript\nhttp.get(url, (res) => {\n const body = []\n res.on('data', (chunk) => {\n body.push(chunk.toString())\n }).on('end', () => {\n const html = body.join()\n console.log(html)\n })\n})\n```\n\nКак видно из примера выше, объект `response` представляет из себя `eventEmitter`\nс событиями `data` и `end`. Первое вызывается после получения очередного чанка с\nданными, второе вызывается после того, как все данные пришли и нужно обозначить\nконец обработки.\n\n## Buffer\n\nИз кода сбора чанков в `body` можно сделать вывод, что `chunk` – это не строка. Это\nдействительно так, `chunk` – это объект типа `Buffer`, который предназначен для\nхранения потока байтов в виде массива фиксированного размера. Нужно это по той простой\nпричине, что данные, передаваемые по `http`, не обязательно имеют текстовое представление.\nВозможна передача также и бинарных данных, таких как картинки, архивы и тому подобное.\n\n```javascript\nconst str = 'string as bytes'\nconst buffer = new Buffer(str, 'utf-8')\nconsole.log(buffer)\n// <Buffer 73 74 72 69 6e 67 20 61 73 20 62 79 74 65 73>\nbuffer.toString()\n// string as bytes\n```\n\n## Errors\n\nВо время выполнения запроса может произойти все, что угодно. Библиотека `http`\nобрабатывает эти ошибки и кидает соответствующие исключения. К таким ошибкам относятся например:\n\n* Проблемы с `DNS`\n* Ошибки уровня `tcp`\n* Ошибки парсинга `http` ответа\n\nЕсли для программы важно не завершаться в случае таких ошибок, то можно ловить\nсобытие `error` на объекте `request`, который возвращается после выполнения `get`\nзапроса и производить желаемое действие:\n\n```javascript\nimport http from 'http'\n\nconst uri = 'http://ru.hexlet.io/my'\n\nconst req = http.get(uri, (res) => {\n console.log(res.statusCode)\n})\n\nreq.on('error', (e) => {\n console.log(`Got error: ${e.message}`)\n})\n```\n"},"lessonMember":null,"courseMember":null,"course":{"start_lesson":{"exercise":null,"units":[{"id":1580,"name":"theory","url":"/courses/js-sync/lessons/intro/theory_unit"}],"links":[],"ordered_units":[{"id":1580,"name":"theory","url":"/courses/js-sync/lessons/intro/theory_unit"}],"id":779,"slug":"intro","state":"approved","name":"Введение","course_order":100,"goal":"Знакомимся с курсом, темой и проектом","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"Первое, с чем мы сталкиваемся в `js` при работе с `IO` – это\nколбеки, сложность использования которых резко нарастает с увеличением\nзависимостей.\n\n```javascript\nimport fs from 'fs'\n\nconst myFile = '/tmp/test'\nfs.readFile(myFile, 'utf8', (err, txt) => {\n if (err) {\n return console.log(err)\n }\n\n const newTxt = `${txt}'\\nAppended something!`\n fs.writeFile(myFile, newTxt, (err) => {\n if (err) {\n return console.log(err)\n }\n console.log('Appended text!')\n })\n})\n```\n\nИ мы знаем уже как минимум один способ борьбы с этой сложностью и даже\nнаписали реализацию нескольких функций библиотеки `async`.\n\n```javascript\nasync.filter(['file1', 'file2'], (filePath, callback) => {\n fs.access(filePath, (err) => {\n callback(null, !err)\n })\n}, (err, results) => {\n // results now equals an array of the existing files\n})\n```\n\nЭтот способ довольно неплох, но обладает рядом недостатков. Один из\nосновных связан с тем, что необходимо знать большое количество разнообразных\nфункций на все случаи жизни. Другой – с тем, что комбинирование\nфункций самой библиотеки `async` приводит к громоздкому коду, который, к\nтому же, не так просто понимать.\n\nОказывается, что существует ряд других способов работы с асинхронным кодом,\nчасть из которых может быть реализована без поддержки со стороны языка.\n\n* Promise (Futures)\n* Coroutines (using Generators)\n* Async/Await\n\nВ этом курсе будут подробно рассмотрены перечисленные концепции, которые\nстали неотъемлемой частью современной разработки на `js`. В процессе\nзнакомства с ними мы построим библиотеку для выполнения `http` запросов.\nОна будет основана на промисах, а использовать ее можно будет с генераторами\nи async/await конструкциями.\n\n```javascript\nimport { get } from 'hexlet-http-request'\n\nexport default async () => {\n const hostname = 'localhost:3000'\n const id = await get(`${hostname}/id`)\n const group = await get(`${hostname}/group`)\n\n return get(`${hostname}/${group}/${id}`)\n}\n```\n\nКак видите, здесь используется новый синтаксис, но сама структура читается хорошо\nдаже без его знания. Код выглядит линейным и не использует колбеки.\n\nДополнительно в курсе будет рассмотрен следующий набор тем:\n\n* Формат данных `json`\n* Итераторы\n* Атаки в сети (CSRF)\n* Модули `nodejs`: `querystring`, `url`, `http`\n"},"id":132,"slug":"js-sync","challenges_count":0,"name":"JS: Синхронная асинхронность","allow_indexing":true,"state":"approved","course_state":"finished","pricing_type":"free","description":"На этом курсе вы изучите, как в JavaScript писать асинхронный код как синхронный. Вы узнаете, как использовать асинхронные функции и промисы для управления асинхронным кодом. Вы научитесь использовать async/await и узнаете, как обрабатывать ошибки в асинхронном коде. Знания из этого курса помогут вам писать более чистый и понятный код, работать с асинхронными операциями и повышать производительность вашего кода.","kind":"sandbox","updated_at":"2026-01-20T11:53:51.389Z","language":"javascript","duration_cache":9360,"skills":["Создавать объекты-генераторы для эмуляции бесконечных потоков","Использовать корутины для асинхронного кода","Строить код на промисах и async/await","Использовать модуль HTTP для выполнения запросов из Node.js"],"keywords":["http","промисы","корутины","генераторы","async/await"],"lessons_count":9,"cover":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6OTAzMCwicHVyIjoiYmxvYl9pZCJ9fQ==--e0d07f03e83d29ad3173e428d803e1c32b468021/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJqcGciLCJyZXNpemVfdG9fZmlsbCI6WzYwMCw0MDBdfSwicHVyIjoidmFyaWF0aW9uIn19--39ba06fa99226096df9fc6bb31f84e1d29ea98e9/image.png"},"recommendedLandings":[],"lessonMemberUnit":null,"accessToLearnUnitExists":true,"accessToCourseExists":true},"url":"/courses/js-sync/lessons/request-get/theory_unit","version":"8f286f6358a90a7bef2263b3a6edf5a90a94fa42","encryptHistory":false,"clearHistory":false}"><style data-mantine-styles="true">:root, :host{--mantine-font-family: Arial, sans-serif;--mantine-font-family-headings: Arial, sans-serif;--mantine-heading-font-weight: normal;--mantine-radius-default: 0rem;--mantine-primary-color-filled: var(--mantine-color-indigo-filled);--mantine-primary-color-filled-hover: var(--mantine-color-indigo-filled-hover);--mantine-primary-color-light: var(--mantine-color-indigo-light);--mantine-primary-color-light-hover: var(--mantine-color-indigo-light-hover);--mantine-primary-color-light-color: var(--mantine-color-indigo-light-color);--mantine-spacing-xxl: calc(4rem * var(--mantine-scale));--mantine-font-size-xs: 12px;--mantine-font-size-sm: 14px;--mantine-font-size-md: 16px;--mantine-font-size-lg: clamp(16.0000px, calc(15.2727px + 0.2273vw), 18.0000px);--mantine-font-size-xl: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-font-size-display-3: clamp(32.0000px, calc(26.1818px + 1.8182vw), 48.0000px);--mantine-font-size-display-2: clamp(36.0000px, calc(25.8182px + 3.1818vw), 64.0000px);--mantine-font-size-display-1: clamp(40.0000px, calc(25.4545px + 4.5455vw), 80.0000px);--mantine-font-size-h1: clamp(28.0000px, calc(23.6364px + 1.3636vw), 40.0000px);--mantine-font-size-h2: clamp(24.0000px, calc(21.0909px + 0.9091vw), 32.0000px);--mantine-font-size-h3: clamp(20.0000px, calc(17.0909px + 0.9091vw), 28.0000px);--mantine-font-size-h4: clamp(16.0000px, calc(13.0909px + 0.9091vw), 24.0000px);--mantine-font-size-h5: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-font-size-h6: 1rem;--mantine-primary-color-0: var(--mantine-color-indigo-0);--mantine-primary-color-1: var(--mantine-color-indigo-1);--mantine-primary-color-2: var(--mantine-color-indigo-2);--mantine-primary-color-3: var(--mantine-color-indigo-3);--mantine-primary-color-4: var(--mantine-color-indigo-4);--mantine-primary-color-5: var(--mantine-color-indigo-5);--mantine-primary-color-6: var(--mantine-color-indigo-6);--mantine-primary-color-7: var(--mantine-color-indigo-7);--mantine-primary-color-8: var(--mantine-color-indigo-8);--mantine-primary-color-9: var(--mantine-color-indigo-9);--mantine-color-red-0: #ffeaea;--mantine-color-red-1: #fed4d4;--mantine-color-red-2: #f4a7a8;--mantine-color-red-3: #ec7878;--mantine-color-red-4: #e55050;--mantine-color-red-5: #e03131;--mantine-color-red-6: #e02829;--mantine-color-red-7: #c71a1c;--mantine-color-red-8: #b21218;--mantine-color-red-9: #9c0411;--mantine-color-violet-0: #fce9ff;--mantine-color-violet-1: #f1cfff;--mantine-color-violet-2: #e09bff;--mantine-color-violet-3: #d16fff;--mantine-color-violet-4: #be37fe;--mantine-color-violet-5: #b51afe;--mantine-color-violet-6: #b009ff;--mantine-color-violet-7: #9b00e4;--mantine-color-violet-8: #8a00cc;--mantine-color-violet-9: #7800b3;--mantine-color-indigo-0: #edecff;--mantine-color-indigo-1: #d6d5fe;--mantine-color-indigo-2: #aaa9f4;--mantine-color-indigo-3: #7b79eb;--mantine-color-indigo-4: #5451e4;--mantine-color-indigo-5: #3b37e0;--mantine-color-indigo-6: #2d2adf;--mantine-color-indigo-7: #1f1ec7;--mantine-color-indigo-8: #1819b2;--mantine-color-indigo-9: #0c149e;--mantine-color-cyan-0: #dffdff;--mantine-color-cyan-1: #caf5ff;--mantine-color-cyan-2: #99e8ff;--mantine-color-cyan-3: #64daff;--mantine-color-cyan-4: #3ccffe;--mantine-color-cyan-5: #24c8fe;--mantine-color-cyan-6: #00c2ff;--mantine-color-cyan-7: #00ade4;--mantine-color-cyan-8: #009acd;--mantine-color-cyan-9: #0085b5;--mantine-color-green-0: #e9fdec;--mantine-color-green-1: #d7f6dc;--mantine-color-green-2: #b0eab9;--mantine-color-green-3: #86df94;--mantine-color-green-4: #62d574;--mantine-color-green-5: #4ccf5f;--mantine-color-green-6: #3fcc54;--mantine-color-green-7: #2fb344;--mantine-color-green-8: #25a03b;--mantine-color-green-9: #138a2e;--mantine-color-yellow-0: #fff7e2;--mantine-color-yellow-1: #ffeecd;--mantine-color-yellow-2: #ffdc9c;--mantine-color-yellow-3: #ffc966;--mantine-color-yellow-4: #feb93a;--mantine-color-yellow-5: #feae1e;--mantine-color-yellow-6: #ffa90f;--mantine-color-yellow-8: #ca8200;--mantine-color-yellow-9: #af7000;--mantine-h1-font-size: clamp(28.0000px, calc(23.6364px + 1.3636vw), 40.0000px);--mantine-h1-font-weight: normal;--mantine-h2-font-size: clamp(24.0000px, calc(21.0909px + 0.9091vw), 32.0000px);--mantine-h2-font-weight: normal;--mantine-h3-font-size: clamp(20.0000px, calc(17.0909px + 0.9091vw), 28.0000px);--mantine-h3-font-weight: normal;--mantine-h4-font-size: clamp(16.0000px, calc(13.0909px + 0.9091vw), 24.0000px);--mantine-h4-font-weight: normal;--mantine-h5-font-size: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-h5-font-weight: normal;--mantine-h6-font-size: 1rem;--mantine-h6-font-weight: normal;}
:root[data-mantine-color-scheme="dark"], :host([data-mantine-color-scheme="dark"]){--mantine-color-anchor: var(--mantine-color-text);--mantine-color-dimmed: #495057;--mantine-color-dark-filled: var(--mantine-color-dark-5);--mantine-color-dark-filled-hover: var(--mantine-color-dark-6);--mantine-color-dark-light: rgba(105, 105, 105, 0.15);--mantine-color-dark-light-hover: rgba(105, 105, 105, 0.2);--mantine-color-dark-light-color: var(--mantine-color-dark-0);--mantine-color-dark-outline: var(--mantine-color-dark-1);--mantine-color-dark-outline-hover: rgba(184, 184, 184, 0.05);--mantine-color-gray-filled: var(--mantine-color-gray-5);--mantine-color-gray-filled-hover: var(--mantine-color-gray-6);--mantine-color-gray-light: rgba(222, 226, 230, 0.15);--mantine-color-gray-light-hover: rgba(222, 226, 230, 0.2);--mantine-color-gray-light-color: var(--mantine-color-gray-0);--mantine-color-gray-outline: var(--mantine-color-gray-1);--mantine-color-gray-outline-hover: rgba(241, 243, 245, 0.05);--mantine-color-red-filled: var(--mantine-color-red-5);--mantine-color-red-filled-hover: var(--mantine-color-red-6);--mantine-color-red-light: rgba(236, 120, 120, 0.15);--mantine-color-red-light-hover: rgba(236, 120, 120, 0.2);--mantine-color-red-light-color: var(--mantine-color-red-0);--mantine-color-red-outline: var(--mantine-color-red-1);--mantine-color-red-outline-hover: rgba(254, 212, 212, 0.05);--mantine-color-pink-filled: var(--mantine-color-pink-5);--mantine-color-pink-filled-hover: var(--mantine-color-pink-6);--mantine-color-pink-light: rgba(250, 162, 193, 0.15);--mantine-color-pink-light-hover: rgba(250, 162, 193, 0.2);--mantine-color-pink-light-color: var(--mantine-color-pink-0);--mantine-color-pink-outline: var(--mantine-color-pink-1);--mantine-color-pink-outline-hover: rgba(255, 222, 235, 0.05);--mantine-color-grape-filled: var(--mantine-color-grape-5);--mantine-color-grape-filled-hover: var(--mantine-color-grape-6);--mantine-color-grape-light: rgba(229, 153, 247, 0.15);--mantine-color-grape-light-hover: rgba(229, 153, 247, 0.2);--mantine-color-grape-light-color: var(--mantine-color-grape-0);--mantine-color-grape-outline: var(--mantine-color-grape-1);--mantine-color-grape-outline-hover: rgba(243, 217, 250, 0.05);--mantine-color-violet-filled: var(--mantine-color-violet-5);--mantine-color-violet-filled-hover: var(--mantine-color-violet-6);--mantine-color-violet-light: rgba(209, 111, 255, 0.15);--mantine-color-violet-light-hover: rgba(209, 111, 255, 0.2);--mantine-color-violet-light-color: var(--mantine-color-violet-0);--mantine-color-violet-outline: var(--mantine-color-violet-1);--mantine-color-violet-outline-hover: rgba(241, 207, 255, 0.05);--mantine-color-indigo-filled: var(--mantine-color-indigo-5);--mantine-color-indigo-filled-hover: var(--mantine-color-indigo-6);--mantine-color-indigo-light: rgba(123, 121, 235, 0.15);--mantine-color-indigo-light-hover: rgba(123, 121, 235, 0.2);--mantine-color-indigo-light-color: var(--mantine-color-indigo-0);--mantine-color-indigo-outline: var(--mantine-color-indigo-1);--mantine-color-indigo-outline-hover: rgba(214, 213, 254, 0.05);--mantine-color-blue-filled: var(--mantine-color-blue-5);--mantine-color-blue-filled-hover: var(--mantine-color-blue-6);--mantine-color-blue-light: rgba(116, 192, 252, 0.15);--mantine-color-blue-light-hover: rgba(116, 192, 252, 0.2);--mantine-color-blue-light-color: var(--mantine-color-blue-0);--mantine-color-blue-outline: var(--mantine-color-blue-1);--mantine-color-blue-outline-hover: rgba(208, 235, 255, 0.05);--mantine-color-cyan-filled: var(--mantine-color-cyan-5);--mantine-color-cyan-filled-hover: var(--mantine-color-cyan-6);--mantine-color-cyan-light: rgba(100, 218, 255, 0.15);--mantine-color-cyan-light-hover: rgba(100, 218, 255, 0.2);--mantine-color-cyan-light-color: var(--mantine-color-cyan-0);--mantine-color-cyan-outline: var(--mantine-color-cyan-1);--mantine-color-cyan-outline-hover: rgba(202, 245, 255, 0.05);--mantine-color-teal-filled: var(--mantine-color-teal-5);--mantine-color-teal-filled-hover: var(--mantine-color-teal-6);--mantine-color-teal-light: rgba(99, 230, 190, 0.15);--mantine-color-teal-light-hover: rgba(99, 230, 190, 0.2);--mantine-color-teal-light-color: var(--mantine-color-teal-0);--mantine-color-teal-outline: var(--mantine-color-teal-1);--mantine-color-teal-outline-hover: rgba(195, 250, 232, 0.05);--mantine-color-green-filled: var(--mantine-color-green-5);--mantine-color-green-filled-hover: var(--mantine-color-green-6);--mantine-color-green-light: rgba(134, 223, 148, 0.15);--mantine-color-green-light-hover: rgba(134, 223, 148, 0.2);--mantine-color-green-light-color: var(--mantine-color-green-0);--mantine-color-green-outline: var(--mantine-color-green-1);--mantine-color-green-outline-hover: rgba(215, 246, 220, 0.05);--mantine-color-lime-filled: var(--mantine-color-lime-5);--mantine-color-lime-filled-hover: var(--mantine-color-lime-6);--mantine-color-lime-light: rgba(192, 235, 117, 0.15);--mantine-color-lime-light-hover: rgba(192, 235, 117, 0.2);--mantine-color-lime-light-color: var(--mantine-color-lime-0);--mantine-color-lime-outline: var(--mantine-color-lime-1);--mantine-color-lime-outline-hover: rgba(233, 250, 200, 0.05);--mantine-color-yellow-filled: var(--mantine-color-yellow-5);--mantine-color-yellow-filled-hover: var(--mantine-color-yellow-6);--mantine-color-yellow-light: rgba(255, 201, 102, 0.15);--mantine-color-yellow-light-hover: rgba(255, 201, 102, 0.2);--mantine-color-yellow-light-color: var(--mantine-color-yellow-0);--mantine-color-yellow-outline: var(--mantine-color-yellow-1);--mantine-color-yellow-outline-hover: rgba(255, 238, 205, 0.05);--mantine-color-orange-filled: var(--mantine-color-orange-5);--mantine-color-orange-filled-hover: var(--mantine-color-orange-6);--mantine-color-orange-light: rgba(255, 192, 120, 0.15);--mantine-color-orange-light-hover: rgba(255, 192, 120, 0.2);--mantine-color-orange-light-color: var(--mantine-color-orange-0);--mantine-color-orange-outline: var(--mantine-color-orange-1);--mantine-color-orange-outline-hover: rgba(255, 232, 204, 0.05);--app-cta-gradient: linear-gradient(90deg, var(--mantine-color-blue-9) 0%, var(--mantine-color-cyan-7) 100%);--app-color-surface: #2e2e2e;}
:root[data-mantine-color-scheme="light"], :host([data-mantine-color-scheme="light"]){--mantine-color-anchor: var(--mantine-color-text);--mantine-color-dimmed: #495057;--mantine-color-red-light: rgba(224, 40, 41, 0.1);--mantine-color-red-light-hover: rgba(224, 40, 41, 0.12);--mantine-color-red-outline-hover: rgba(224, 40, 41, 0.05);--mantine-color-violet-light: rgba(176, 9, 255, 0.1);--mantine-color-violet-light-hover: rgba(176, 9, 255, 0.12);--mantine-color-violet-outline-hover: rgba(176, 9, 255, 0.05);--mantine-color-indigo-light: rgba(45, 42, 223, 0.1);--mantine-color-indigo-light-hover: rgba(45, 42, 223, 0.12);--mantine-color-indigo-outline-hover: rgba(45, 42, 223, 0.05);--mantine-color-cyan-light: rgba(0, 194, 255, 0.1);--mantine-color-cyan-light-hover: rgba(0, 194, 255, 0.12);--mantine-color-cyan-outline-hover: rgba(0, 194, 255, 0.05);--mantine-color-green-light: rgba(63, 204, 84, 0.1);--mantine-color-green-light-hover: rgba(63, 204, 84, 0.12);--mantine-color-green-outline-hover: rgba(63, 204, 84, 0.05);--mantine-color-yellow-light: rgba(255, 169, 15, 0.1);--mantine-color-yellow-light-hover: rgba(255, 169, 15, 0.12);--mantine-color-yellow-outline-hover: rgba(255, 169, 15, 0.05);--app-color-surface: #f1f3f5;--app-cta-gradient: linear-gradient(90deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-5) 100%);}</style><style data-mantine-styles="classes">@media (max-width: 35.99375em) {.mantine-visible-from-xs {display: none !important;}}@media (min-width: 36em) {.mantine-hidden-from-xs {display: none !important;}}@media (max-width: 47.99375em) {.mantine-visible-from-sm {display: none !important;}}@media (min-width: 48em) {.mantine-hidden-from-sm {display: none !important;}}@media (max-width: 61.99375em) {.mantine-visible-from-md {display: none !important;}}@media (min-width: 62em) {.mantine-hidden-from-md {display: none !important;}}@media (max-width: 74.99375em) {.mantine-visible-from-lg {display: none !important;}}@media (min-width: 75em) {.mantine-hidden-from-lg {display: none !important;}}@media (max-width: 87.99375em) {.mantine-visible-from-xl {display: none !important;}}@media (min-width: 88em) {.mantine-hidden-from-xl {display: none !important;}}</style><div style="position:absolute;top:0rem" class=""></div><div style="max-width:var(--container-size-xl);height:100%;min-height:0rem" class=""><style data-mantine-styles="inline">.__m__-_R_5ub_{--grid-gutter:0rem;}</style><div style="height:100%;min-height:0rem" class="m_410352e9 mantine-Grid-root __m__-_R_5ub_"><div class="m_dee7bd2f mantine-Grid-inner" style="height:100%"><style data-mantine-styles="inline">.__m__-_R_rdub_{--col-flex-grow:auto;--col-flex-basis:91.66666666666667%;--col-max-width:91.66666666666667%;}@media(min-width: 48em){.__m__-_R_rdub_{--col-flex-grow:auto;--col-flex-basis:83.33333333333334%;--col-max-width:83.33333333333334%;}}</style><div style="min-width:0rem;height:100%;min-height:0rem;display:flex" class="m_96bdd299 mantine-Grid-col __m__-_R_rdub_"><style data-mantine-styles="inline">.__m__-_R_6qrdub_{margin-top:0rem;padding-inline:var(--mantine-spacing-xs);width:100%;}@media(min-width: 48em){.__m__-_R_6qrdub_{margin-top:var(--mantine-spacing-xl);width:80%;}}@media(min-width: 62em){.__m__-_R_6qrdub_{padding-inline:var(--mantine-spacing-xl);}}</style><div style="margin-inline:auto;max-width:var(--mantine-breakpoint-xl)" class="__m__-_R_6qrdub_"><div style="color:var(--mantine-color-dimmed)" class="m_4451eb3a mantine-Center-root" data-inline="true"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;margin-inline-end:calc(0.125rem * var(--mantine-scale));color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-lock "><path d="M5 13a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v6a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-6"></path><path d="M11 16a1 1 0 1 0 2 0a1 1 0 0 0 -2 0"></path><path d="M8 11v-4a4 4 0 1 1 8 0v4"></path></svg></div><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">JS: Синхронная асинхронность</p></div><h1 style="--title-fw:var(--mantine-h1-font-weight);--title-lh:var(--mantine-h1-line-height);--title-fz:var(--mantine-h1-font-size);margin-bottom:var(--mantine-spacing-xl)" class="m_8a5d1357 mantine-Title-root" data-order="1">Теория: GET-запрос</h1><script type="application/ld+json">{"@context":"https://schema.org","@type":"LearningResource","name":"GET-запрос","inLanguage":"ru","isPartOf":{"@type":"LearningResource","name":"JS: Синхронная асинхронность"},"isAccessibleForFree":"False","hasPart":{"@type":"WebPageElement","isAccessibleForFree":"False","cssSelector":".paywalled"}}</script><div class=""><div style="--alert-color:var(--mantine-color-indigo-light-color);margin-bottom:var(--mantine-spacing-lg);font-size:var(--mantine-font-size-lg)" class="m_66836ed3 mantine-Alert-root" id="mantine-_R_remqrdub_" role="alert" aria-describedby="mantine-_R_remqrdub_-body" aria-labelledby="mantine-_R_remqrdub_-title"><div class="m_a5d60502 mantine-Alert-wrapper"><div class="m_667f2a6a mantine-Alert-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-rocket "><path d="M4 13a8 8 0 0 1 7 7a6 6 0 0 0 3 -5a9 9 0 0 0 6 -8a3 3 0 0 0 -3 -3a9 9 0 0 0 -8 6a6 6 0 0 0 -5 3"></path><path d="M7 14a6 6 0 0 0 -3 6a6 6 0 0 0 6 -3"></path><path d="M14 9a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"></path></svg></div><div class="m_667c2793 mantine-Alert-body"><div class="m_6a03f287 mantine-Alert-title"><span id="mantine-_R_remqrdub_-title" class="m_698f4f23 mantine-Alert-label">Полный доступ к материалам</span></div><div id="mantine-_R_remqrdub_-body" class="m_7fa78076 mantine-Alert-message"><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:space-between;--group-wrap:wrap" class="m_4081bf90 mantine-Group-root"><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Зарегистрируйтесь и получите доступ к этому и десяткам других курсов</p><a style="--button-height:var(--button-height-xs);--button-padding-x:var(--button-padding-x-xs);--button-fz:var(--mantine-font-size-xs);--button-bg:linear-gradient(45deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-filled) 100%);--button-hover:linear-gradient(45deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-filled) 100%);--button-color:var(--mantine-color-white);--button-bd:none" class="mantine-focus-auto mantine-active m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root" data-variant="gradient" data-size="xs" href="/u/new"><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label">Зарегистрироваться</span></span></a></div></div></div></div></div><div class="paywalled m_d08caa0 mantine-Typography-root"><p>Предположим, что мы хотим программно выполнить <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">get</code> запрос к Хекслету.
В <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">nodejs</code> сделать это довольно просто:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">import http from 'http'
http.get('http://ru.hexlet.io/my', (res) => {
console.log(res.statusCode)
})</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Вторым параметром передается колбек, который будет вызван после получения
ответа. Он также принимает на вход объект <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">response</code>, который содержит
в себе параметры ответа.</p>
<p>Этих параметров внутри <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">response</code> очень много, и только некоторые из них
наиболее часто используются или могут быть нам интересны. В первую очередь
это следующий набор:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">// response
{
headers: /* ... */,
statusCode: 301,
statusMessage: 'Moved Permanently',
};</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Также <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">get</code> позволяет передавать первым параметром не адрес, а набор
опций, из которого будет составлен адрес. Такое бывает полезно, когда
у нас нет готового адреса, но есть его части:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">import http from 'http'
// headers, method, port, ...
const options = {
hostname: 'ru.hexlet.io',
path: 'my',
}
http.get(options, (res) => {
console.log(res.statusCode)
})</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Обо всех доступных опциях можно прочитать в официальной документации, а
из самых распространенных мы выделим следующие:</p>
<ul>
<li>headers — объект, в котором ключ — это название заголовка</li>
<li>method — например, <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">GET</code></li>
<li>port</li>
<li>hostname</li>
<li>path</li>
</ul>
<h2 id="heading-2-1">Body</h2>
<p>В запросе выше не хватает одной важной детали: получение тела ответа.
Тут нас поджидает небольшой сюрприз. Объект <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">response</code> не содержит внутри
себя тело ответа. Связано это с тем, что ответ может приходить чанками,
и <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">response</code> дает возможность получать эти чанки сразу и независимо друг от друга.
С одной стороны, это более гибкая возможность, которая позволяет работать с большим
телом, без того чтобы занимать много оперативной памяти; с другой стороны, для
простых запросов приходится доставать тело немного более сложным способом, чем хотелось
бы. Но, в конечном итоге, все сводится к понятному коду, который нужно просто запомнить.</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">http.get(url, (res) => {
const body = []
res.on('data', (chunk) => {
body.push(chunk.toString())
}).on('end', () => {
const html = body.join()
console.log(html)
})
})</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Как видно из примера выше, объект <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">response</code> представляет из себя <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">eventEmitter</code>
с событиями <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">data</code> и <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">end</code>. Первое вызывается после получения очередного чанка с
данными, второе вызывается после того, как все данные пришли и нужно обозначить
конец обработки.</p>
<h2 id="heading-2-2">Buffer</h2>
<p>Из кода сбора чанков в <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">body</code> можно сделать вывод, что <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">chunk</code> – это не строка. Это
действительно так, <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">chunk</code> – это объект типа <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">Buffer</code>, который предназначен для
хранения потока байтов в виде массива фиксированного размера. Нужно это по той простой
причине, что данные, передаваемые по <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">http</code>, не обязательно имеют текстовое представление.
Возможна передача также и бинарных данных, таких как картинки, архивы и тому подобное.</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">const str = 'string as bytes'
const buffer = new Buffer(str, 'utf-8')
console.log(buffer)
// <Buffer 73 74 72 69 6e 67 20 61 73 20 62 79 74 65 73>
buffer.toString()
// string as bytes</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<h2 id="heading-2-3">Errors</h2>
<p>Во время выполнения запроса может произойти все, что угодно. Библиотека <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">http</code>
обрабатывает эти ошибки и кидает соответствующие исключения. К таким ошибкам относятся например:</p>
<ul>
<li>Проблемы с <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">DNS</code></li>
<li>Ошибки уровня <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">tcp</code></li>
<li>Ошибки парсинга <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">http</code> ответа</li>
</ul>
<p>Если для программы важно не завершаться в случае таких ошибок, то можно ловить
событие <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">error</code> на объекте <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">request</code>, который возвращается после выполнения <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">get</code>
запроса и производить желаемое действие:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">import http from 'http'
const uri = 'http://ru.hexlet.io/my'
const req = http.get(uri, (res) => {
console.log(res.statusCode)
})
req.on('error', (e) => {
console.log(`Got error: ${e.message}`)
})</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div></div></div></div></div><style data-mantine-styles="inline">.__m__-_R_1bdub_{--col-flex-grow:auto;--col-flex-basis:8.333333333333334%;--col-max-width:8.333333333333334%;}@media(min-width: 48em){.__m__-_R_1bdub_{--col-flex-grow:auto;--col-flex-basis:16.666666666666668%;--col-max-width:16.666666666666668%;}}</style><div style="min-width:0rem;height:100%;min-height:0rem" class="m_96bdd299 mantine-Grid-col __m__-_R_1bdub_"><div style="margin-inline:var(--mantine-spacing-xs)" class="mantine-visible-from-sm"><a style="--button-color:var(--mantine-color-white);margin-bottom:var(--mantine-spacing-lg);text-decoration:none" class="mantine-focus-auto m_849cf0da mantine-focus-auto m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses/js-sync/lessons/request-get/finish_unit?unit=theory" data-disabled="true" data-block="true" disabled=""><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label"><span style="margin-inline-end:var(--mantine-spacing-xs)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Дальше</span>→</span></span></a><a style="padding-inline:0rem" class="mantine-focus-auto m_f0824112 mantine-NavLink-root m_87cf2631 mantine-UnstyledButton-root"><span class="m_690090b5 mantine-NavLink-section" data-position="left"><div style="--ti-size:var(--ti-size-sm);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="sm"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-list-numbers "><path d="M11 6h9"></path><path d="M11 12h9"></path><path d="M12 18h8"></path><path d="M4 16a2 2 0 1 1 4 0c0 .591 -.5 1 -1 1.5l-3 2.5h4"></path><path d="M6 10v-6l-2 2"></path></svg></div></span><div class="m_f07af9d2 mantine-NavLink-body"><span class="m_1f6ac4c4 mantine-NavLink-label">Навигация по теме</span><span class="m_57492dcc mantine-NavLink-description">Теория</span></div><span class="m_690090b5 mantine-NavLink-section" data-position="right"></span></a><div style="margin-block:var(--mantine-spacing-lg)" class="m_3eebeb36 mantine-Divider-root" data-orientation="horizontal" role="separator"></div><div style="margin-block:var(--mantine-spacing-lg)" class=""><div style="justify-content:space-between;margin-bottom:calc(0.1875rem * var(--mantine-scale));color:var(--mantine-color-dimmed);font-size:var(--mantine-font-size-xs)" class="m_8bffd616 mantine-Flex-root __m__-_R_qimrbdub_"><p style="font-size:var(--mantine-font-size-xs)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Завершено</p><p style="font-size:var(--mantine-font-size-xs)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">0 / 9</p></div><div style="--progress-size:var(--progress-size-sm)" class="m_db6d6462 mantine-Progress-root" data-size="sm"><div style="--progress-section-size:0%;--progress-section-color:var(--mantine-color-gray-filled)" class="m_2242eb65 mantine-Progress-section" role="progressbar" aria-valuemax="100" aria-valuemin="0" aria-valuenow="0" aria-valuetext="0%"></div></div></div><button style="padding-inline:0rem" class="mantine-focus-auto m_f0824112 mantine-NavLink-root m_87cf2631 mantine-UnstyledButton-root" type="button"><span class="m_690090b5 mantine-NavLink-section" data-position="left"><div style="--ti-size:var(--ti-size-sm);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="sm"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-message "><path d="M8 9h8"></path><path d="M8 13h6"></path><path d="M18 4a3 3 0 0 1 3 3v8a3 3 0 0 1 -3 3h-5l-5 3v-3h-2a3 3 0 0 1 -3 -3v-8a3 3 0 0 1 3 -3h12"></path></svg></div></span><div class="m_f07af9d2 mantine-NavLink-body"><span class="m_1f6ac4c4 mantine-NavLink-label">Обсуждения (архив)</span><span class="m_57492dcc mantine-NavLink-description"></span></div></button><div style="--toc-bg:var(--mantine-color-blue-light);--toc-color:var(--mantine-color-blue-light-color);--toc-size:var(--mantine-font-size-sm);--toc-radius:var(--mantine-radius-sm);margin-top:var(--mantine-spacing-xl)" class="m_bcaa9990 mantine-TableOfContents-root" data-variant="light" data-size="sm"></div></div><div class="mantine-hidden-from-sm"><div style="--stack-gap:0rem;--stack-align:stretch;--stack-justify:flex-start" class="m_6d731127 mantine-Stack-root"><a style="--button-color:var(--mantine-color-white);margin-bottom:var(--mantine-spacing-xs);padding:0rem;text-decoration:none" class="mantine-focus-auto m_849cf0da mantine-focus-auto m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses/js-sync/lessons/request-get/finish_unit?unit=theory" data-disabled="true" data-block="true" disabled=""><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label">→</span></span></a><button style="--ai-size:var(--ai-size-sm);--ai-bg:transparent;--ai-hover:var(--mantine-color-indigo-light-hover);--ai-color:var(--mantine-color-indigo-light-color);--ai-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;padding-block:var(--mantine-spacing-lg);color:inherit;width:100%" class="mantine-focus-auto m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="subtle" data-size="sm" data-disabled="true" type="button" disabled=""><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-list-numbers "><path d="M11 6h9"></path><path d="M11 12h9"></path><path d="M12 18h8"></path><path d="M4 16a2 2 0 1 1 4 0c0 .591 -.5 1 -1 1.5l-3 2.5h4"></path><path d="M6 10v-6l-2 2"></path></svg></span></button><button style="--ai-size:var(--ai-size-sm);--ai-bg:transparent;--ai-hover:var(--mantine-color-indigo-light-hover);--ai-color:var(--mantine-color-indigo-light-color);--ai-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;padding-block:var(--mantine-spacing-lg);color:inherit;width:100%" class="mantine-focus-auto mantine-active m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="subtle" data-size="sm" type="button"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-message "><path d="M8 9h8"></path><path d="M8 13h6"></path><path d="M18 4a3 3 0 0 1 3 3v8a3 3 0 0 1 -3 3h-5l-5 3v-3h-2a3 3 0 0 1 -3 -3v-8a3 3 0 0 1 3 -3h12"></path></svg></span></button></div></div></div></div></div></div></div>
</main>
<footer class="bg-dark fw-light text-light px-3 py-5">
<div class="row small">
<div class="col-12 col-sm-6 col-md-3">
<div class="h5 mb-3">Хекслет</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/about">О нас</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/testimonials">Отзывы</a>
</li>
<li>
<span class="nav-link link-light py-1 ps-0 external-link" data-href="https://b2b.hexlet.io" role="button">Корпоративное обучение</span>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/blog">Блог</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/qna">Вопросы и ответы</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/glossary">Глоссарий</a>
</li>
<li>
<span class="nav-link link-light py-1 ps-0 external-link" data-href="https://help.hexlet.io" data-target="_blank" role="button">Справка</span>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" target="_blank" rel="noopener noreferrer" href="/map">Карта сайта</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5 fw-normal mb-3">Направления</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_devops">DevOps
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_data_analytics">Аналитика
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_backend_development">Бэкенд
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_programming">Программирование
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_testing">Тестирование
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_front_end_dev">Фронтенд
</a></li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5">Профессии</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/devops-engineer-from-scratch">DevOps-инженер с нуля</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/go">Go-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/java">Java-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/python">Python-разработчик </a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/data-analytics">Аналитик данных</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/qa-engineer">Инженер по ручному тестированию</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/php">РНР-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/frontend">Фронтенд-разработчик</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5">Навыки</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/python-django-developer">Django</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/docker">Docker</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/php-laravel-developer">Laravel</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/postman">Postman</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/js-react-developer">React</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/js-rest-api">REST API в Node.js</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/spring-boot">Spring Boot</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/typescript">Typescript</a>
</li>
</ul>
</div>
</div>
<hr>
<div class="row">
<div class="col-12 col-sm-4 col-md-2">
<div class="fs-4">
<ul class="list-unstyled d-flex">
<li class="me-3">
<a aria-label="Telegram" target="_blank" class="link-light" rel="noopener noreferrer nofollow" href="https://t.me/hexlet_ru"><span class="bi bi-telegram"></span>
</a></li>
<li>
<a aria-label="Youtube" target="_blank" class="link-light" rel="noopener noreferrer nofollow" href="https://www.youtube.com/user/HexletUniversity"><span class="bi bi-youtube"></span>
</a></li>
</ul>
</div>
<div class="mb-2 d-flex flex-column">
<a class="link-light text-decoration-none" rel="nofollow" href="mailto:support@hexlet.io">support@hexlet.io</a>
<a class="link-light text-decoration-none py-2" target="_blank" href="https://t.me/hexlet_help_bot">t.me/hexlet_help_bot</a>
</div>
<ul class="list-unstyled d-flex">
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 external-link" rel="nofollow" data-href="https://hexlet.io/locale/switch?new_locale=en" data-target="_self" role="button"><span class="my-auto">EN</span>
</span></li>
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 opacity-100 external-link" rel="nofollow" data-href="https://ru.hexlet.io/locale/switch?new_locale=ru" data-target="_self" role="button"><span class="my-auto">RU</span>
</span></li>
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 external-link" rel="nofollow" data-href="https://kz.hexlet.io/locale/switch?new_locale=kz" data-target="_self" role="button"><span class="my-auto">KZ</span>
</span></li>
</ul>
</div>
<div class="col-12 col-sm-4 col-md-3">
<ul class="list-unstyled fs-4">
<li class="mb-3">
<a class="link-light text-decoration-none" href="tel:8%20800%20100%2022%2047">8 800 100 22 47</a>
<span class="d-block opacity-50 small">бесплатно по РФ</span>
</li>
<li>
<a class="link-light text-decoration-none" href="tel:%2B7%20495%20085%2021%2062">+7 495 085 21 62</a>
<span class="d-block opacity-50 small">бесплатно по Москве</span>
</li>
</ul>
</div>
<div class="col-12 col-sm-4 col-md-3">
<div class="small mb-3">Образовательные услуги оказываются на основании Л035-01298-77/01989008 от 14.03.2025</div>
<ul class="list-unstyled small">
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/legal">Правовая информация</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/offer">Оферта</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/license">Лицензия</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/contacts">Контакты</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-12 col-md-4 small">
<div class="mb-2">
<div>ООО «<a href="/" class="text-decoration-none link-light">Хекслет Рус</a>»</div>
<div>108813 г. Москва, вн.тер.г. поселение Московский,</div>
<div>г. Московский, ул. Солнечная, д. 3А, стр. 1, помещ. 20Б/3</div>
<div>ОГРН 1217300010476</div>
<div>ИНН 7325174845</div>
</div>
<hr>
<div>АНО ДПО «<a href="/" class="text-decoration-none link-light">Учебный центр «Хекслет</a>»</div>
<div>119331 г. Москва, вн. тер. г. муниципальный округ</div>
<div>Ломоносовский, пр-кт Вернадского, д. 29</div>
<div>ОГРН 1247700712390</div>
<div>ИНН 7736364948</div>
</div>
</div>
</footer>
<div id="root-assistant-offcanvas"></div>
<script src="/vite/assets/assistant-Bukl1lYy.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/init-BrRXra1y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ErrorFallbackBlock-naDSYSy9.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/MarkdownBlock-DbyKWoR_.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/gon-D3e4yh1x.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/mantine-CGMYrt2Y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/shiki-V011pkdv.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/utils-DRqSHbQE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/lib-XR8Qr8kR.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dist-GCHh59xr.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Box-B5-OOzBf.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/notifications.store-C-3AFSMn.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useIsomorphicEffect-HJ6VK0D3.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/lib-KSp6QbZ0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/axios-BEvgo0ym.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/classnames-l6ipYlLR.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dayjs.min-BkKovM-s.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/debounce-jMQ_Cf4f.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/i18next-BlSq9s7B.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/client-U9M77rxp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-dom-DaLxUz_h.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useTranslation-Bx1Cdrkz.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/compiler-runtime-6XxiPFnt.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/jsx-runtime-CwjcCKJi.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-CkL4ZRHB.js" as="script" crossorigin="anonymous">
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v67327c56f0bb4ef8b305cae61679db8f1769101564043" integrity="sha512-rdcWY47ByXd76cbCFzznIcEaCN71jqkWBBqlwhF1SY7KubdLKZiEGeP7AyieKZlGP9hbY/MhGrwXzJC/HulNyg==" data-cf-beacon='{"version":"2024.11.0","token":"d11015b65d11429ea6b4a2ef37dd7e0b","server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}' crossorigin="anonymous"></script>
</body>
</html>