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).
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ