From 0a7f093837d980a38eb064c916d62dc16351662c Mon Sep 17 00:00:00 2001 From: Vladimir Chebukin Date: Fri, 13 Jun 2025 11:07:13 +0300 Subject: [PATCH] Add lesson 16 and lesson 17 --- lessons/lesson16/lesson.md | 334 +++++++++++++++++++++++++++++++++++++ lessons/lesson17/lesson.md | 218 ++++++++++++++++++++++++ 2 files changed, 552 insertions(+) diff --git a/lessons/lesson16/lesson.md b/lessons/lesson16/lesson.md index 4d0ab1e..156eb28 100644 --- a/lessons/lesson16/lesson.md +++ b/lessons/lesson16/lesson.md @@ -1 +1,335 @@ # Lesson 16 + +--- + +title: Занятие 16 +description: Базовое использование API и JavaScript. Как работать с сетевыми ресурсами + +--- + +# OTUS + +## Javascript Basic + + + +### Вопросы? + + + +### Базовое использование API и JavaScript. + +#### Как работать с сетевыми ресурсами + + + +### Асинхронный код - минимум для работы + +_Подробнее будет в третьем модуле на занятии про асинхронный код_ + + + +#### JS - ОДНОПОТОЧНЫЙ ЯЗЫК + +- Отрисовка DOM +- Обработка пользовательского ввода +- Выполнение JS кода + + + +#### [ОЧЕРЕДЬ ЗАДАЧ В JS](https://developer.mozilla.org/ru/docs/Web/JavaScript/EventLoop) + +- Среда выполнения содержит очередь событий (список событий, подлежащих обработке) +- Каждое событие ассоциируется с некоторой функцией. +- Каждый вызов функции добавляет запись в стек +- При завершении функции запись изымается из стека +- Когда стек освобождается, событие извлекается из очереди и обрабатывается (функция вызывается). + + + +На бытовом уровне мы могли бы это объяснить так... + + + +[Демонстрация](https://codesandbox.io/s/github/vvscode/otus--javascript-basic/tree/lesson04/lessons/lesson04/code/singleThreadInJs?file=/index.html) + + + +Поэтому операции, которые занимают длительное (больше 50 ms) операции стараются + +- переложить на внешнего исполнителя +- отложить исполнение и разбить на части + + + +Так появляется **асинхронный код** - когда результат вы получаете не немедленно, а отложено во времени. + + + +Как работать с таким асинхронным кодом? Как это выглядит? + + + +```js [1-30] +// работа с callback-функциями +const x = 2; +// результат мы можем обработать в callback-функции +calculateSomethingAsyncWithCallback(x, (result) => { + console.log(result); +}); +// в node.js было принято +calculateSomethingAsyncWithCallback(x, (error, result) => { + if (error) { + return console.error(error); + } + // ... +}); +``` + + + +```js [1-30] +// работа с callback-функциями +const x = 2; +calculateSomethingAsyncWithCallback(x, (result) => { + calculateSomethingElseAsyncWithCallback(result, (secondResult) => { + console.log(result); + }); +}); +``` + + + +### Вопросы? + + + +Для решения проблемы [callback hell](http://callbackhell.com/) ввели интерфейс [Promise](https://developer.mozilla.org/ru/docs/Web/JavaScript/Guide/Ispolzovanie_promisov). + + + +```js [1-30] +function doSomething() { + return new Promise((resolve, reject) => { + console.log("Готово."); + // Успех в половине случаев. + if (Math.random() > 0.5) { + resolve("Успех"); + } else { + reject("Ошибка"); + } + }); +} + +const promise = doSomething(); +promise.then(successCallback, failureCallback); +promise.then(successCallback).catch(failureCallback); +``` + + + +```js [1-30] +calculateSomethingAsyncWithPromise(x) + .then((result) => calculateSomethingElseAsyncWithPromise(result)) + .then((secondResult) => console.log(secondResult)); +``` + + + +### Вопросы? + + + +Но в Javascript приходит все больше и больше людей с других языков, и им непривычно читать такой код. Кроме того он имеет некоторые проблемы (например нам нужен одновременный доступ к `result` и `secondResult`). + + + +Появились `async` функции. Которые предоставляют [`await` механизм](https://learn.javascript.ru/async-await). + + + +Мы можем пометить функцию ключевым словом async. Это дает следующее: + +1. функция теперь неявно возвращает Promise + +1. внутри функции мы можем использовать ключевое слово `await` для разворачивания Promise-результатов + + + +```js [1-30] +(async function () { + const x = 2; + const result = await calculateSomethingAsyncWithPromise(x); + const secondResult = await calculateSomethingElseAsyncWithPromise(result); + console.log(secondResult); +})(); +``` + + + +[Top-level await](https://github.com/tc39/proposal-top-level-await). + +```js [1-30] +const x = 2; +const result = await calculateSomethingAsyncWithPromise(x); +const secondResult = await calculateSomethingElseAsyncWithPromise(result); +console.log(secondResult); +``` + + + +Краткий итог: + +- некоторый функции нужно вызывать с ключевым словом `await` +- `await` работает только внутри функций, которые помечены как `async` и в top-level + +Подробнее мы будем разбирать на занятии про асинхронность + + + +### Вопросы? + + + +В разработке принято писать на уровне интерфейсов (абстракций), а не реализаций. То есть вы должны знать ЧТО делает функция или модуль, но не КАК. + +Когда вы начинаете использовать детали реализации - это называется "протекающая абстракция". + + + +Типичные кандидаты на асинхронные операции: + +- запрос данных от пользователя +- сохранение и чтение данных +- обращение к стороннему сервису +- валидации и сложные вычисления + + + +Но при этом + +- для запроса данных от пользователя есть синхронные `alert` / `prompt` +- для чтения и сохранения данных есть синхронный `localStorage` + + + +Лучше сразу заложить возможность для расширения, и использовать асинхронные обертки. Тогда в любой момент можно будет поменять реализацию, и вместо `localStorage` сохранять данные на сервере, например. А вместо `alert` показывать красивое стилизованное модальное окно (которое не блокирует поток). + + + +```js [1-30] +async function asyncPrompt(request) { + return prompt(request); +} +// const x = asyncPrompt(); работать не будет +const x = await asyncPrompt(); +``` + + + +### Вопросы? + + + +### [Работа со сторонними сервисами](https://learn.javascript.ru/network) + + + +Для работы с HTTP запросами у нас есть два варианта (на самом деле больше, если подключать библиотеки): + +- [XMLHttpRequest](https://learn.javascript.ru/xmlhttprequest) +- [fetch](https://learn.javascript.ru/fetch) + + + +`fetch` - поддерживается современными браузерами, предоставляет Promise-based интерфейс (удобен для `async` функций) и прост в использовании. + + + +```js [1-30] +// await-friendly окружение +let response = await fetch(url); + +let text = await response.text(); + +console.log(text); +``` + + + +```js [1-30] +// await-friendly окружение +let response = await fetch("https://jsonplaceholder.typicode.com/users"); + +let jsonData = await response.json(); +console.log(jsonData); +``` + + + +`fetch` возвращает вам объект типа [`Response`](https://developer.mozilla.org/ru/docs/Web/API/Response). + +Чаще всего используются + +- поле `ok` +- поле `status` +- методы `text()` и `json()` + + + +### Вопросы? + + + +[Практика](https://codesandbox.io/s/github/vvscode/otus--javascript-basic/tree/lesson04/lessons/lesson04/code/fetchPractice) + +[OpenWeather API](https://openweathermap.org/current) + + + +### Вопросы? + + + +Дополнительное задание: + +при заходе на страницу показать пользователю погоду в его городе. Для получения этой информации можно сделать запрос на `https://get.geojs.io/v1/ip/geo.json`, который вернет данные в формате JSON. + +[GeoAPI](https://www.geojs.io/docs/v1/endpoints/geo/) + + + +Если вы хотите собрать все вместе, можете выполнить следующий проект (его уже можно показывать друзьям). + +[Сайт с прогонозом погоды](https://github.com/vvscode/otus--javascript-basic/blob/master/lessons/lesson09/homework.md) + +Само домашнее задание у вас будет позже, но уже сейчас вы можете выполнять часть, связанную со страницей. + + + +### Вопросы? + + + +#### Дополнительные материалы + + + +1. [Путеводитель по JavaScript Promise для новичков](https://habr.com/ru/company/zerotech/blog/317256/) +2. [Public APIs](https://github.com/public-apis/public-apis#open-source-projects) +3. [JavaScript. Как работать с API Telegram, Youtube и VK](https://live.ithillel.ua/javascript.-rabota-s-api) +4. [Что на самом деле происходит, когда пользователь вбивает в браузер адрес google.com](https://habr.com/ru/company/htmlacademy/blog/254825/) + + + +#### Вопросы для самопроверки + +1. Что такое CORS? + +2. Что такое и какие есть коды ответов HTTP? + +3. Что такое jsonp-запрос? + +4. Быть в состоянии рассказать что такое XHR, AJAX, CDN + +5. Чем XMLHTTPRequest отличается от fetch? diff --git a/lessons/lesson17/lesson.md b/lessons/lesson17/lesson.md index 9e1f3f4..f78ef9c 100644 --- a/lessons/lesson17/lesson.md +++ b/lessons/lesson17/lesson.md @@ -1 +1,219 @@ # Lesson 17 + +--- + +title: Занятие 17 +description: Базовая работа с сетью: методы HTTP, куки, заголовки, WS + +--- + +# OTUS + +## Javascript Basic + + + +### Вопросы? + + + +### Базовая работа с сетью: методы HTTP, куки, заголовки, WS. + + + +HTTP сообщения - это обмен данными между сервером и клиентом. Есть два типа сообщений: _запросы_, отправляемые клиентом, чтобы инициировать реакцию со стороны сервера, и _ответы_ от сервера. + + + +HTTP-сообщение представляет собой обычный текст. Структура сообщения строго определена: + +1. Стартовая строка +2. Метод запроса +3. Заголовки, передают сервисную информацию +4. Тело сообщения, представляет данные в текстовом виде + + + +HTTPS (HTTP Secure) является **зашифрованной** версией HTTP протокола. Обычно он использует SSL или TLS для шифрования соединения между клиентом и сервером. + + + +### Вопросы? + + + +URL состоит из различных частей, некоторые из которых являются обязательными, а некоторые - опциональными. + +``` +http://www.example.com:80/path/to/myfile.html?key1=value1&key2=value2#SomewhereInTheDocument +``` + +1. `http://` - протокол +2. `www.example.com` - доменное имя +3. `:80` - порт +4. `path/to/myfile.html` - адрес ресурса на веб-сервере +5. `?key1=value1&key2=value2` - дополнительные параметры, которые браузер сообщает веб-серверу +6. `#SomewhereInTheDocument` - якорь на другую часть того же самого ресурса + + + +- **GET** - Позволяет запросить некоторый конкретный ресурс +- **POST** - Позволяет отправить данные на сервер +- **PUT** - Используется для создания новых ресурсов на сервере +- **DELETE** - Позволяет удалить существующие ресурсы на сервере +- **PATCH** - Позволяет внести частичные изменения в указанный ресурс по указанному расположению +- **HEAD** - Cлужит для проверки существования ресурса +- **OPTIONS** - Cлужит для получения параметров для ресурса или для сервера в целом. + + + +- _1xx_ — обработка данных на сервере продолжается; +- _2xx_ — успешная обработка данных; +- _3xx_ — перенаправление запросов; +- _4xx_ — ошибка по вине клиента; +- _5xx_ — ошибка по вине сервера. + + + +- _200 OK_ в случае успешной обработки запроса. +- _301 Moved Permanently_ если редирект используется на постоянной основе. +- _307 Temporary Redirect_ если редирект используется временно. +- _400 Bad Request_ если в запросе есть синтаксическая ошибка. +- _403 Forbidden_ если запрос успешный, но сервер его не может выполнить, поскольку пользователь не имеет достаточных прав. +- _404 Not Found_ если запрошенного ресурса не существует. +- _500 Internal Server Error_ если работа программы на сервере выдала ошибку. + + + +1. Основные заголовки, которые могут включаться в любые сообщения клиента и сервера. +2. Заголовки запроса, которые используются только в сообщениях клиента. +3. Заголовки ответа, которые используются только в сообщениях сервера. +4. Заголовки сущности, которые описывают данные в сообщении. + + + +1. _Via_ содержит версию HTTP протокола +1. _User-Agent_ содержит строку с типом браузера и ОС +1. _Content-Length_ - указывает размер отправленного получателю тела объекта в байтах. +1. _Сontent-Type_ - используется для того, чтобы определить тип ресурса. +1. _Cookie_ - содержит куки + + + +```js [1-30] +const response = await fetch("https://jsonplaceholder.typicode.com/posts", { + method: "POST", + body: JSON.stringify({ + title: "Заголовок поста", + body: "А роза упала на лапу азора", + userId: 1, + }), + headers: { + "Content-type": "application/json; charset=UTF-8", + }, +}); + +const data = await response.json(); +console.log(data); +``` + + + +Куки – это небольшие текстовые данные, которые хранятся в браузере пользователя и используются веб-сайтами для запоминания информации о посетителе. + + + +- _path_ — определяет путь, по которому будет доступна кука. +- _domain_ — определяет домен, для которого указана кука. +- _max-age_ и _expires_ — определяет время жизни куки. +- _secure_ — указывает, что данная кука может быть передана только при запросах по защищённому протоколу HTTPS. +- _samesite_ — определяет, может ли данная кука быть отправлена при кроссдоменном запросе. + + + +```js [1-30] +document.cookie = "showOnboarding=true;max-age=3600"; +``` + + + +### Вопросы? + + + +### WebSocket + + + +- Протокол для постоянного двунаправленного соединения между клиентом и сервером +- Отличие от HTTP: постоянное соединение вместо запроса-ответа +- Используется для чатов, игр, обновления данных в реальном времени + + + +- Установка соединения через HTTP-апгрейд (Handshake) +- После успешного рукопожатия открывается двунаправленный канал +- Обмен сообщениями в формате текста или бинарных данных +- Закрытие соединения + + + +```js [1-30] +const socket = new WebSocket("wss://echo.websocket.org"); + +socket.onopen = () => { + console.log("Соединение открыто"); + socket.send("Привет, WebSocket!"); +}; + +// socket.send(...) + +socket.onmessage = (event) => { + console.log("Получено сообщение:", event.data); +}; + +socket.onclose = () => { + console.log("Соединение закрыто"); +}; + +socket.onerror = (error) => { + console.error("Ошибка WebSocket:", error); +}; +``` + + + +- Чаты и мессенджеры +- Онлайн-игры +- Финансовые торги и обновление котировок +- Мониторинг и телеметрия в реальном времени + + + +### Вопросы? + + + +#### Дополнительные материалы + + + +1. [Модель OSI](https://habr.com/ru/articles/876628/) +2. [Путеводитель по HTTP](https://developer.mozilla.org/ru/docs/Web/HTTP) +3. [HTTP заголовки](https://developer.mozilla.org/ru/docs/Web/HTTP/Reference/Headers) +4. [HTTP методы](https://developer.mozilla.org/ru/docs/Web/HTTP/Reference/Methods) +5. [Cookies](https://developer.mozilla.org/ru/docs/Web/HTTP/Guides/Cookies) + + + +#### Вопросы для самопроверки + +1. Что происходит на уровне протокола при выполнении HTTP-запроса от клиента к серверу? + +2. Какие параметры куки влияют на безопасность и область действия куки в браузере? + +3. Как можно ограничить доступ к куки с помощью атрибута HttpOnly? + +4. Как работает механизм установки и передачи куки между клиентом и сервером? + +5. Чем WebSocket отличается от традиционных HTTP-запросов и в каких сценариях его использование наиболее оправдано?