Розуміння асинхронного JavaScript: від Callback Hell до Async/Await

Природжена асинхронна природа JavaScript дозволяє нам виконувати неблокуючі операції, такі як мережеві запити, файл I/O та інші. Однак керувати цими операціями може бути складно. Цей блог проведе вас через еволюцію обробки асинхронних операцій у JavaScript, починаючи з колбеків (callbacks) і переходячи до promises та async/await.

pic

Проблема з колбеками: Callback Hell

Колбеки були початковим способом обробки асинхронних операцій у JavaScript. Колбек — це функція, яка передається як аргумент іншій функції, яка буде виконана пізніше. Хоча це було зрозуміло для простих завдань, колбеки можуть стати громіздкими, коли вони вкладені.

Приклад Callback Hell

getUser(userId, (user) => {  
 getPosts(user.id, (posts) => {  
 getComments(posts[0].id, (comments) => {  
 console.log(comments);  
 });  
 });  
});

Чому це проблема:

  • Вкладена структура: Важко читати та підтримувати.
  • Обробка помилок: Складно передавати та керувати помилками.

Від Callback Hell до Promises

Promises були введені для вирішення цих проблем. Promise представляє значення, яке може бути доступне зараз, в майбутньому, або ніколи.

Приклад використання Promises

getUser(userId)  
 .then((user) => getPosts(user.id))  
 .then((posts) => getComments(posts[0].id))  
 .then((comments) => console.log(comments))  
 .catch((error) => console.error(error));

Переваги:

  • Спрощена структура: Легше читати та налагоджувати.
  • Ланцюгування: Дозволяє чистіший потік асинхронних операцій.
  • Обробка помилок: catch() обробляє помилки на будь-якому етапі.

Створення Promises

Створення власних promises дозволяє інкапсулювати асинхронну логіку.

Приклад кастомного Promise

const fetchData = () => {  
 return new Promise((resolve, reject) => {  
 setTimeout(() => {  
 const data = "Fetched data!";  
 resolve(data);  
 }, 1000);  
 });  
};  

fetchData()  
 .then((data) => console.log(data))  
 .catch((error) => console.error(error));

Використання Promises з Async/Await

Async/await, введений у ES2017, побудований на promises і надає синтаксис, подібний до синхронного, для обробки асинхронного коду.

Приклад Async/Await

const fetchComments = async (userId) => {  
 try {  
 const user = await getUser(userId);  
 const posts = await getPosts(user.id);  
 const comments = await getComments(posts[0].id);  
 console.log(comments);  
 } catch (error) {  
 console.error(error);  
 }  
};  

fetchComments(1);

Чому використовувати async/await?

  • Читабельність: Код лінійний і простий для розуміння.
  • Обробка помилок: Використовуйте try...catch для чистішого управління помилками.

Повернення значень з Async функцій

Async функції завжди повертають promise. Щоб отримати повернуте значення, потрібно використовувати await або .then().

Приклад

const addNumbers = async (a, b) => a + b;  

addNumbers(3, 7).then((result) => console.log(result)); // Виведеться: 10

Очікування кількох Promises одночасно

Ви можете використовувати Promise.all або Promise.allSettled для одночасного виконання кількох promises.

Приклад Promise.all

const fetchAllData = async () => {  
 const userPromise = getUser(1);  
 const postsPromise = getPosts(1);  

 const [user, posts] = await Promise.all([userPromise, postsPromise]);  
 console.log(user, posts);  
};  

fetchAllData();

Чому використовувати?

  • Покращує продуктивність, запускаючи promises паралельно.
  • Спрощує обробку кількох асинхронних операцій.

Висновок

JavaScript зробив великий крок від колбеків до async/await. Кожен етап зробив асинхронне програмування більш керованим та менш схильним до помилок. Зрозумівши та використовуючи promises і async/await, ви можете писати більш чистий, ефективний та легший для підтримки код.

Який підхід ви надаєте перевагу і чому? Поділіться своїми думками в коментарях!

Перекладено з: Understanding Asynchronous JavaScript: From Callback Hell to Async/Await

Leave a Reply

Your email address will not be published. Required fields are marked *