// поток выполнения идет последовательно от строки к строке
const div = document.querySelector('div'); // запускается эта строка
div.innerHTML = <p>Всем привет</p> // после запускается эта строка
console.log(div); // после запускается эта строка и так далее
// Такие длительные операции как alert блокируют код
alert(div.textContent = 'Всем привет');
// пока мы не нажем ok на появившемся окне, выполнение кода будет заблокировано
Поэтому если у нас есть длительная операция на сайте, то весь код будет заблокирован и мы ничего не сможем сделать. Для таких ситуаций нам и нужен асинхронный код.
Операция с callback
функцией:
const div = document.querySelector('div'); // синхронный код
setTimeout(()=> { // асинхронный код
div.textContent = 'Всем пока';
},2000)
div.textContent = 'Всем привет' // синхронный код
const div = document.querySelector('div');
setTimeout
и код не остановит свое выполнение, запуск таймера будет в фоновом режиме. Поток выполнения просто регистрирует эту функцию и сразу выполняет следующую строку кода.setTimeout(()=> {
div.textContent = 'Всем пока';
},2000) // 2000 миллисекунд - 2 секунды
// Пока таймер отсчитывает время, выполнение кода не останавливается, поэтому это неблокирующий код.
div.textContent = 'Всем привет';
div.textContent = 'Всем пока'; // наша строка из setTimeout
callback функции не есть обязательно асинхронные, есть также и синхронные - они универсальны.
Пример синхронного callback с MDN
:
const gods = ['Apollo', 'Artemis', 'Ares', 'Zeus'];
gods.forEach(function (eachName, index){ // callback функция ничего не ждет, она выполняется сразу
console.log(index + '. ' + eachName);
});
AJAX
— это аббревиатура, которая означает Asynchronous Javascript and XML
.
AJAX
позволяет нам асинхронно работать с веб-серверами. С помощью AJAX
мы можем динамически запрашивать данные с веб-серверов.
Если понятнее то, мы можем получить данные, при этом страница не будет обновляться.
Клиент(браузер) создает запрос(request - get/post), на веб-сервер и мы получаем ответ(response) отправку данных - все это происходит в асинхронном режиме.
Работает это с помощью некого API
которое работает на сервере и принимает запросы на данные и отправляет данные обратно в качестве ответа. Подробнее тут .
API
(Application programming interface) - это часть программы, которая может использоваться другой программой, чтобы приложения могли взаимодействовать друг с другом. В веб-разработке существует множество типов API
.
Например DOM API
- с помощью которого мы взаимодействуем с html
. Объект document
- это интерфейс DOM API
.
XMLHttpRequest
с которым мы будем работать дальше - это тоже api
, набор готовых методов и решений.
Get запрос - направлен на то, что бы получить какие то данные от сервера,
в нашем случае мы будем получать курс валюты у нашего current.json
бекенд части (сервер)
get запросы показывают товары например в магазине на сайте.
Post - это постить запросы, например регистрация на сайте, мы вводим наши данные и постим их на сервер, или например когда загружаем файлы.
XMLHttpRequest
уже устаревшее api
, сейчас используется fetch. Но XMLHttpRequest
все еще может встретиться, так же разобравшись в нем fetch
не станет проблемой.
Нашим сервером будет файл current.json
из него мы будем получать курс доллара.
{
"current":{
"usd":74
}
}
У нас будет два инпута.
<div class="calc">
<label for="rub">RUB</label>
<input id="rub" type="text">
<label for="usd">USD</label>
<input id="usd" type="text">
</div>
Получаем элементы и погнали:
const inputRub = document.querySelector('#rub'),
inputUsd = document.querySelector('#usd');
inputRub.addEventListener('input', () => { // событие input сробатывает когда в инпуте что-то меняется
const request = new XMLHttpRequest(); // создали экземпляр с нужными нам свойствами и методами
// XMLHttpRequest - это объект в которомд находятся свойства и методы.
// open(); - этот метод собирает настройки которые в будущем помогут сделать запрос. принимает в себя несколько аргументов.
request.open('GET', 'src/current.json'); // вызываем open() у нашего объекта. Внутрь попещаем аргументы:
/*
1 - method: это тот который используется для запроса(get post и тд)
2 - url: это путь к нашему сервевру. Путь у url строим относительно index.html.
3 - async: этот аргумент отвечает за асинхронность - в нем по умолчанию стоит true, можн опоставить false, но тогда это уже будет синхронный код
4 - login - логин: некоторые запросы мы можем делать только имея пароль и логин
5 - pass - пароль
*/
// Далее вызываем setRequestHeader() - устанавливает значения HTTP заголовков. Вызывается после open() но до send().
// далее send() - отправляем наш запрос. send: принимает в себя body - это данные которые уходят на сервер, но это в Post запросе в get этого нет, потому что мы получаем их. Поэтому send вызываем, но внутрь ничего не передаем.
request.setRequestHeader('Content-type', 'application/json; charset=utf-8'); // говорим что есть опр тип - тут уже сам тип это наш json и далее кодировка, самая стандартная.
request.send(); - просто вызваем.
});
В этих свойствах мы получаем ответ полсе запроса на сервер:
Коды http запросов легко гуглятся. Например код 404 - Not Found. Категория от 400 - 499 относятся к клиенским ошибкам, и тд..
readyState будет возвращать вот такие состояния, где цифры это значение, далее состояние и описание:
0 - UNSENT: Объект был создан. Метод open() ещё не вызывался.
1 - OPENED: Метод open() был вызван.
2 - HEADERS_RECEIVED: Метод send() был вызван, доступны заголовки (headers) и статус.
3 - LOADING: Загрузка. responseText содержит частичные данные.
4 - DONE: Операция полностью завершена.
readystatechange
- следит за свойством readyState
о котором говорили выше.
Например когда запрос изменится с 0
на 1
- сработает событие.
Все это нам позволяет написать условие внутри нашего запроса, что мы писали выше.
request.addEventListener('readystatechange',()=>{ // вызываем событие readystatechange у объекта request.
if (request.readyState === 4 && request.status === 200) { // тут мы узнаем, если у нас 4 - операция завершена и статус 200 - это значит Ок - хорошо
// Так же чаше использует событие load оно срабатывает один раз когда запрос готов.
// мы удалем request.readyState === 4 &&
// остовляя только request.status === 200, а cобытие меняем readystatechange на load
console.log(request.response); // выведем наш объект в консоль. Что бы наглядно увидеть, что это наш json
const data = JSON.parse(request.response); // в data помещаем наш JSON объект и сразу парсим в обычный. он находится в response - ответ от сервера.
inputUsd.value = (+inputRub.value / data.current.usd).toFixed(2); // в инпут usd выводим инпут с рублем деленый на значение usd из нашего объекта
}
else {
inputUsd.value = 'что-то пошло не так';
}
});
Теперь все вместе без моих комментариев:
const inputRub = document.querySelector('#rub'),
inputUsd = document.querySelector('#usd');
inputRub.addEventListener('input', () => {
const request = new XMLHttpRequest();
request.open('GET', 'src/current.json');
request.setRequestHeader('Content-type', 'application/json; charset=utf-8');
request.send();
request.addEventListener('readystatechange', () => {
if (request.readyState === 4 && request.status === 200) {
const data = JSON.parse(request.response);
console.log(request.response);
inputUsd.value = (+inputRub.value / data.current.usd).toFixed(2);
} else {
inputUsd.value = 'что-то пошло не так';
}
});
});
И вот, что получаем: