1.1 Основные концепции асинхронности
Асинхронность в JavaScript позволяет выполнять задачи в фоновом режиме, не блокируя основной поток выполнения. Это особенно важно для задач, которые могут занять значительное время, таких как сетевые запросы, чтение файлов и таймеры. Сейчас мы рассмотрим основные концепции асинхронного программирования в JavaScript и приведем примеры использования.
Однопоточный характер JavaScript
JavaScript является однопоточным языком: это означает, что он выполняет код последовательно в одном потоке. Однако асинхронные операции позволяют выполнять задачи в фоновом режиме, освобождая основной поток для других задач.
Event Loop (Цикл событий)
Цикл событий (Event Loop) является ключевым механизмом, который позволяет JavaScript обрабатывать асинхронные задачи. Цикл событий управляет очередью сообщений (Message Queue) и очередью микрозадач (Microtask Queue), обеспечивая выполнение асинхронных операций.
- Очередь сообщений: содержит задачи, такие как обработчики событий, сетевые запросы и таймеры. Задачи из этой очереди выполняются последовательно.
- Очередь микрозадач: содержит задачи с более высоким приоритетом по сравнению с задачами в очереди сообщений. Примеры включают завершение промисов и вызовы обратных функций (callbacks) в микрозадачах.
Цикл событий постоянно проверяет обе очереди и выполняет задачи из них, когда основной поток становится свободным.
Асинхронные операции
Асинхронные операции позволяют выполнять задачи в фоновом режиме. Основные примеры асинхронных операций включают:
- Таймеры (
setTimeout,setInterval) - Обработчики событий
- Сетевые запросы (например,
XMLHttpRequest,Fetch API) - Чтение/запись файлов (в Node.js)
Давайте рассмотрим несколько примеров асинхронных операций.
1.2 Таймеры
Таймеры позволяют выполнять задачи с задержкой или через регулярные интервалы времени.
Пример использования setTimeout
В этом примере setTimeout устанавливает выполнение функции через 2 секунды. В результате сначала выводится Start и End, а затем через 2 секунды выводится Executed after 2 seconds.
console.log('Start');
setTimeout(() => {
console.log('Executed after 2 seconds');
}, 2000);
console.log('End');
Пример использования setInterval
В этом примере setInterval выполняет функцию каждую секунду, увеличивая счетчик и выводя его значение. Когда счетчик достигает 5, интервал очищается с помощью clearInterval:
let counter = 0;
const intervalID = setInterval(() => {
counter++;
console.log(`Counter: ${counter}`);
if (counter >= 5) {
clearInterval(intervalID);
}
}, 1000);
1.3 Обработчики событий
Обработчики событий позволяют выполнять код в ответ на действия пользователя или другие события.
Пример использования обработчиков событий
В этом примере обработчик события click добавляется к кнопке. Когда пользователь нажимает на кнопку, выводится сообщение Button clicked!:
<!DOCTYPE html>
<html>
<head>
<title>Event Handler Example</title>
</head>
<body>
<button id="myButton">Click me</button>
<script>
const button = document.getElementById('myButton');
button.addEventListener('click', () => {
console.log('Button clicked!');
});
</script>
</body>
</html>
1.4 Сетевые запросы
Сетевые запросы позволяют выполнять асинхронные HTTP-запросы к серверу.
Пример использования XMLHttpRequest
В этом примере создается асинхронный GET-запрос к API, и когда запрос завершен, ответ выводится в консоль:
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1', true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
const response = JSON.parse(xhr.responseText);
console.log(response);
}
};
xhr.send();
1.5 Event Loop в действии
Чтобы лучше понять, как работает Event Loop, рассмотрим следующий пример:
console.log('Start');
setTimeout(() => {
console.log('Timeout 1');
}, 0);
Promise.resolve().then(() => {
console.log('Promise 1');
});
setTimeout(() => {
console.log('Timeout 2');
}, 0);
Promise.resolve().then(() => {
console.log('Promise 2');
});
console.log('End');
Ожидаемый вывод будет следующим:
StartEndPromise 1Promise 2Timeout 1Timeout 2
В этом примере сначала выполняются синхронные операции (console.log('Start') и console.log('End')). Затем выполняются микрозадачи (обработчики промисов), и только после этого выполняются задачи из очереди сообщений (setTimeout).
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ