Что такое асинхронный JavaScript?
Асинхронность просто означает, что множество событий происходит одновременно в любом порядке, не дожидаясь друг друга, и это определение применимо к асинхронному Javascript.
В этой статье я рассмотрю концепцию асинхронного JavaScript, обратного вызова (Callback), промисов (Promises), асинхронности/ожидания (Async/Await), очереди обратного вызова (Callback queue), цикла обработки событий (Event Loop) и функций веб-браузера (Web API).
Javascript — это однопоточный язык, который может запускать только один процесс одновременно. JavaScript использует цикл обработки событий для выполнения операции, на данный момент рассмотрим цикл обработки событий как очередь, в которой все процессы Javascript поддерживаются и выполняются по одному за раз.
Вы должны отметить, что Javascript на самом деле является синхронным языком. JavaScript выполняет строки кода последовательно, а не одновременно, потому что по умолчанию он является синхронным и однопоточным.
Например, приведенный ниже код будет запускаться и выполняться построчно.
let username = "John";
let points = 5000;
let message = `${username} has earned ${points} points`;
console.log(message);
//Output
John has earned 5000 points
Приведенный выше код выполняется синхронно, каждая строка завершается перед переходом к следующей строке.
Давайте рассмотрим сценарий, в котором вам нужно получить большой объем данных из API и отобразить их. По умолчанию в JavaScript выполнение блокируется, и все дальнейшие инструкции приостанавливаются до тех пор, пока запрос на получение не будет выполнен. Именно здесь асинхронное программирование становится решающим.
Давайте углубимся.
Что такое асинхронный JavaScript
Асинхронный JavaScript относится к парадигме программирования, в которой выполнение кода не следует обычному последовательному потоку сверху вниз. Вместо этого асинхронный код позволяет инициировать и выполнять определенные операции отдельно, не блокируя выполнение другого кода.
Концепция асинхронного JavaScript позволяет разбивать большие сложные проекты на более мелкие задачи.
Что входит в асинхронный JavaScript?
- Функции веб-браузера (веб-API).
- Callback очередь
- Цикл событий
- Callback
- Async/Await
- Промисы
Функции веб-браузера (веб-API)
API-интерфейсы браузера, также известные как веб-API, представляют собой уже существующие интерфейсы, встроенные в веб-браузеры. Эти API предлагают встроенные функции, которые можно использовать в веб-приложениях.
Веб-API позволяют разработчикам получать доступ к этим дополнительным функциям и взаимодействовать с ними с помощью JavaScript. Используя веб-API, разработчики могут легко внедрять определенные функции в свою кодовую базу, сводя к минимуму сложность кода. Примерами таких функций являются выполнение сетевых запросов и эффективное управление хранилищем на стороне клиента.
Некоторые функции веб-браузера включают в себя:
setTimeout()
Метод setTimeout()
позволяет запускать блок кода после определенной временной задержки. Он предназначен для однократного выполнения кода.
Синтаксис setTimeout()
:
setTimeout(function, milliseconds);
Пример:
function username() {
console.log("John")
}
setTimeout(username, 5000)
console.log("Doe")
Выход:
Doe
John
setInterval()
Метод setInterval()
повторяет блок кода при каждом заданном временном событии.
Синтаксис setInterval()
:
setInterval(function, milliseconds);
Пример:
// program to display a text using setInterval method
function orderItem() {
console.log('I want a bag');
}
setInterval(orderItem, 1000);
Выход:
I want a bag
I want a bag
I want a bag
I want a bag
...
В приведенной выше программе функция orderItem()
вызывается методом setInterval()
с интервалом в 1000 миллисекунд. Следовательно, программа выводит сообщение «I want a bag» каждую 1 секунду.
clearTimeout()
МетодclearTimeout()
отменяет тайм-аут, ранее установленный вызовомsetTimeout()
.
Синтаксис clearTimeout()
:
clearTimeout(timeoutId)
Пример:
// Set a timeout that logs a message after 3 seconds
const timeoutId = setTimeout(() => {
console.log("Timeout executed!");
}, 3000);
// Clear the timeout before it executes
clearTimeout(timeoutId);
Выход:
Если вы запустите предоставленный фрагмент кода, вывода не будет. Функция clearTimeout()
отменяет выполнение тайм-аута, установленного setTimeout()
, предотвращая вызов функции обратного вызова. В результате сообщение «Timeout executed!» не будет выведено на консоль.
clearInterval()
Метод clearInterval()
используется, если вы хотите остановить вызов функции.
Синтаксис clearInterval()
:
clearInterval(intervalId);
Пример:
// Define a variable to store the interval ID
let intervalId;
// Function to be executed repeatedly
function showMessage() {
console.log("Hello!");
}
// Start the interval
intervalId = setInterval(showMessage, 1000);
// After 5 seconds, stop the interval
setTimeout(() => {
clearInterval(intervalId);
console.log("Interval stopped");
}, 5000);
Выход:
Hello!
Hello!
Hello!
Hello!
Interval stopped
В приведенной выше программе вы сначала объявляете переменную intervalId
для хранения идентификатора, возвращаемого функцией setInterval
. Определена функция showMessage
, которая будет выполняться повторно каждые 1000 миллисекунд (1 секунду) с использованием setInterval
.
Через 5 секунд (5000 миллисекунд) вызывается clearInterval
с intervalId
в качестве аргумента для остановки интервала. Это остановит выполнение функции showMessage
. Наконец, на консоль выводится сообщение о том, что интервал остановлен.
fetch()
Метод fetch()
в JavaScript используется для запроса данных с сервера.
Они не являются частью языка JavaScript, но построены на основе основного языка JavaScript, предоставляя вам дополнительные возможности для использования в коде JavaScript.
Узнайте больше о веб-API 👉 здесь 👈.
Callback очередь
Очередь Callback — это место, куда функция Callback помещается и ожидает выполнения. Очередь Callback следует принципу «первым пришел – первым обслужен» (FIFO).
Теперь давайте рассмотрим этот пример:
function username() {
console.log("John")
}
setTimeout(username, 5000)
console.log("Doe")
//output
Doe
John
Этот блок кода демонстрирует использование функции setTimeout()
для задержки выполнения функции обратного вызова.
Вот как это работает:
- Функция
username
определена и хранится в глобальной памяти, которая записывает строку «Джон» в консоль. - Функция
setTimeout()
вызывается с двумя аргументами. Первый аргумент — это функцияusername
, которая указывает функцию Callback, которую необходимо выполнить, а второй аргумент — это задержка в миллисекундах, которая в данном случае составляет 5000 миллисекунд (или 5 секунд). - После вызова
setTimeout()
код переходит к следующей строке и выводит на консоль строку «Doe». - Строка «Doe» записывается в консоль первой.
- После задержки в 5000 миллисекунд функция
username
выполняется и записывает в консоль строку «John».
Цикл событий
Цикл событий постоянно проверяет, пуст ли стек вызовов. Если стек вызовов пуст, это означает, что в данный момент нет выполняемых функций. В этом случае цикл берет функции, ожидающие в очереди Callback, и помещает их в стек вызовов для выполнения. Цикл событий действует как привратник для очереди Callback.
Цикл событий управляет выполнением кода, чтобы избежать блокировки, позволяя программе продолжать свою работу даже во время выполнения асинхронных задач.
Что такое Callback?
Когда вы передаете функцию в качестве аргумента другой функции, и эта функция вызывается или выполняется внутри внешней функции, ее обычно называют функцией обратного вызова.
Теперь давайте рассмотрим этот пример:
function placeOrder() {
setTimeout(() => {
return (Math.random() * 10) <= 5 ? 'Bag' : 'Shoe';
}, 2000);
}
let order = placeOrder();
console.log('Order is for: ' + order);
//Output
// Order is for: undefined
Здесь, в функции placeOrder
, setTimeout()
запустится через 2 секунды, и к тому времени оператор console.log
уже будет выполнен, напечатанное значение order
не определено.
Теперь вы можете решить эту проблему, записав свое сообщение в консоль только после того, как данные вернутся из placeOrder
. Это можно сделать, передав функцию callback в функцию placeOrder
, которая будет вызываться внутри функции placeOrder
.
function placeOrder(callback) {
setTimeout(() => {
const order = (Math.random() * 10) <= 5 ? 'Bag' : 'Shoe';
callback(order);
}, 2000);
}
placeOrder((order) => {
console.log('Order is for: ' + order);
});
//Output
// Order is for: Bag
Через две секунды будет вызвана функция callback, и оператор консоли будет выполнен с правильным значением порядка.
Вывод функцииplaceOrde
r может отличаться в вашем случае, поскольку вы используетеMath.random()
для определения значения заказа.
Промисы
Промис — это объект в JavaScript, который представляет возможное завершение (или сбой) асинхронной операции и ее результирующее значение.
Промисы упрощают обработку асинхронного кода, упрощая написание и поддержку асинхронных операций, не прибегая к функциям callback или вложенным callback функциям (известным как hell callback).
Callback hell — это термин, используемый для описания ситуации, когда код становится трудно читать и понимать из-за большого количества вложенных функций callback.
Промис может находиться в одном из трех состояний:
- Ожидание: начальное состояние, когда промис создан, а асинхронная операция все еще продолжается.
- Выполнено: состояние, когда асинхронная операция успешно завершена, а промис имеет разрешенное значение.
- Отклонено: состояние, когда асинхронная операция сталкивается с ошибкой или завершается сбоем, а промис имеет причину отклонения.
Есть три основных аспекта промисов.
- Создание промиса
- Обработка промиса
- Цепочка промиса
Создание промисов
Чтобы создать обещание, вы используете конструктор Promise, который принимает функцию (обычно называемую исполнителем) в качестве аргумента. Функция исполнителя имеет два параметра: разрешение и отклонение. В функции-исполнителе вы выполняете свою асинхронную задачу и вызываете разрешение или отклонение в зависимости от результата.
Вот пример создания промиса:
const fetchData = new Promise((resolve, reject) => {
// Simulating asynchronous task (e.g., making an API call)
setTimeout(() => {
const data = { id: 1, name: "John Doe" };
// Fulfilled the promise with the fetched data
resolve(data);
reject(new Error("Failed to fetch data"));
// Alternatively, reject the promise with an error
}, 2000);
});
Обработка промиса
После создания промиса вы можете назначить callback для обработки результата, используя методы then()
и catch()
.
Метод then()
принимает функцию callback в качестве аргумента и управляет выполненным промисом. Он получает разрешенное значение или результат промиса в качестве аргумента.
Метод catch()
используется для обработки отклонения промиса и вызывается, когда промис отклонен, что позволяет обрабатывать любые ошибки, возникшие во время асинхронной операции.
Теперь давайте рассмотрим этот пример:
fetchData
.then((data) => {
// Handle the fulfilled promise (access the resolved value)
console.log("Fetched data:", data);
})
.catch((error) => {
// Handle the rejected promise (access the error)
console.log("Error:", error);
});
Цепочка промисов
Используя метод then()
, вы можете объединить промисы в цепочку, чтобы создать последовательность асинхронных операций. Каждый callback then()
создает новый промис, позволяя вам обработать результат предыдущей операции и перейти к следующей. Цепочка промисов позволяет вам установить более последовательный и читабельный поток асинхронных операций.
fetchData
.then((data) => {
// Handle the first fulfilled promise
console.log("Fetched data:", data);
return someOtherAsyncTask();
// Return a new promise
})
.then((result) => {
// Handle the result of the second fulfilled promise
console.log("Second async task result:", result);
})
.catch((error) => {
// Handle any errors in the chain
console.log("Error:", error);
});
Async/Await
Async/Await — относительно недавнее дополнение к JavaScript, представленное в ES8, которое предоставляет средства для написания асинхронного кода синхронным образом.
Если вы используете ключевое слово Async
перед определением функции, вы можете использовать await внутри функции. Await
дает вам возможность приостановить функцию неблокирующим образом, пока промис не будет разрешен.
Теперь давайте рассмотрим этот пример:
async function fetchData() {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
const data = await response.json();
console.log('Fetched data:', data);
} catch (error) {
console.log('Error fetching data:', error);
}
}
fetchData();
Вот пояснение к фрагменту кода:
- Объявляется асинхронная функция
fetchUserData()
. Внутри этой функции выполняется асинхронный HTTP-запрос к конечной точке API с помощью функцииfetch()
. Функцияfetch()
возвращает промис, который преобразуется в объект ответа. - Выполнение приостанавливается с помощью ключевого слова
await
, позволяя коду дождаться разрешения промиса, возвращенногоfetch()
. Разрешенный объект ответа сохраняется в переменнойresponse
. - Другое ключевое слово
await
используется для приостановки выполнения и ожидания промиса, возвращаемого методомresponse.json()
. Этот метод анализирует тело ответа как JSON. Затем проанализированные данные JSON сохраняются в переменнойdata
. - Наконец, полученные пользовательские данные записываются в консоль. Если во время выполнения асинхронной функции возникают какие-либо ошибки, они фиксируются в блоке
catch
, что позволяет обрабатывать и регистрировать ошибки.
Заключение
В этой статье вы узнали, что такое асинхронный JavaScript и как писать асинхронный JavaScript, используя промисы и async/await. Вы также увидели, как отправлять запросы с помощью fetch API и async/await и как возвращать ответ на асинхронные вызовы.
В JavaScript синхронные инструкции всегда имеют приоритет над асинхронными. Например, если у вас есть сценарий с многочисленными операторамиconsole.log
, за которыми следует функцияsetTimeout()
продолжительностью 0 миллисекунд, все операторыconsole.log
будут выполняться первыми передsetTimeout()
.
Надеюсь, эта статья была информативной? Вы можете поставить лайк или оставить комментарий о том, что вы думаете.
Я доступен в Twitter, LinkedIn или GitHub. Следите за моим предстоящим блогом, в котором я рассмотрю еще одну важную область веб-разработки. Как разработчик, я рад предоставить дополнительную информацию. А пока удачного кодирования и берегите себя!
Ресурсы
Вот несколько блогов/сообщений, которые я читал в качестве справки, вы должны их проверить: