Асинхронный JavaScript для начинающих
Основа современной веб-разработки – асинхронное выполнение кода. В небольшой статье разберемся, как освоить этот подход, используя JavaScript. Обсудить Перевод публикуется с сокращениями, автор оригинальной статьи Devanshi Tank. Однопоточные языки, такие как JavaScript, могут одновременно выполнять только одну задачу, что приводит к ненужным задержкам. Медленные функции блокируют дальнейшее выполнение кода. Чтобы избежать всего этого, необходим асинхронный JavaScript. Для понимания асинхронности недостаточно знать только core JavaScript. Движок JS состоит из трех основных частей: Можно добавить в этот список API браузеров, Promises, Eventloop, Task queue и Microtask queue. Как мы знаем, JavaScript работает в браузере, а браузер – это мощная программа, предоставляющая множество функций, некоторые из которых делают возможным асинхронный код. Вот эти возможности браузера: Dev Tools, Console, Sockets, Network Requests, Rendering (HTML DOM), Timer и т. д. JavaScript включает в себя набор функций, которые выглядят обычными, но на самом деле являются средством взаимодействия с веб-браузером. Примерами таких функций являются: Попробуем разобраться в следующем фрагменте кода: Определение функции Тем временем таймер работает: как только он завершит свою работу, вызовется функция Это был простой пример, но что делать, когда нужно выполнить тысячи строк асинхронного кода? Необходимы некоторые правила, чтобы поток выполнения работал как нужно. В приведенном примере, поскольку таймер равен 0 мс, можно было бы предположить, что он немедленно запускает printHello, но этого не происходит. Для этого JavaScript есть Callback Queue. Как только все будет сделано, Event Loop извлекает функцию Функция Большая часть нашего кода JavaScript выполняется с помощью функций браузера, но у нас нет доступа к скрытому в его глубине бекенду. Новая возможность ES6 обещает помочь получить некоторую согласованность между происходящим в фоновом режиме и нашей фактической памятью JavaScript, чтобы обрабатывать результат. В ES5 использовалась Промисы можно лучше понять, опираясь на два подхода. Первый указывает на выполняемые через функции браузера фоновые процессы, а второй является отслеживающим запросом объекта Promise в памяти. Использование этих двух подходов поможет сделать следующее: Приведенный фрагмент иллюстрирует простой promise. Получаемое нами обратно из запроса значение хранится в Функция Он также инициирует функцию браузера Network Request для отправки запроса HTTP и получения ответа. Все это вместе с запросом хранится в переменной Мы также должны понять, какова цель На данном этапе может возникнуть вопрос, как добавить функцию к Еще один важный нюанс – обработка ошибок в Мы можем использовать метод Наконец, нам нужно знать, как Promise-deferred функция возвращается в JavaScript для выполнения. В JS есть функция, очень похожая на Callback queue, которая называется Microtask Queue. Пока выполняется сетевой запрос и извлекаются данные, функция, связанная с объектом Как только все данные из ответа получены, она извлекается из Microtask Queue, попадает в callstack через event loop и выполняется. Microtask Queue имеет более высокий приоритет, чем очередь Callback, поэтому функции, связанные с другими асинхронными функциями (вроде Мы рассмотрели важную и ответственную тему и надеемся, что статья окажется для вас полезной. В «Библиотеке программиста» есть несколько материалов, которые помогут ее дополнить: Не останавливайтесь на достигнутом и удачи в обучении!
function printHello() { console.log('Hello'); } setTimeOut(printHello, 1000); console.log('Me First');
printHello
будет сохранено в глобальной памяти. Функция setTimeOut
установит таймер на 1000 мс, чтобы вызвать после его завершения printHello
. Как только setTimeOut
все это проделает, произойдет переход на следующую строку и консоль выведет «Me First».printHello
. Поток управления вернется JavaScript, и напечатается «Hello».
function printHello() { console.log('Hello'); } function blockfor1sec() { //блокирует поток на одну секунду } setTimeOut(printHello, 0); blockfor1sec(); console.log('Me First');
printHello
помещается в нее и остается там до тех пор, пока движок JS не выполнит весь синхронный код. Event Loop проверяет стек вызовов на пустоту, а также завершено ли выполнение всего глобального кода. printHello
из очереди обратного вызова и помещает ее в стек вызовов.
console --------- Me first Hello
printHello
выполняется после глобального кода. С этим подходом есть некоторые проблемы. Предположим, что функция в setTimeOut
извлекает некоторые данные из API, а затем запускает другую функцию с этими данными, которые мы не сможем контролировать. Это происходит, поскольку данная функция автоматизирована с помощью setTimeOut
. Информация, которую она несет и возвращаемый ответ ограничены ею же. С этой ситуацией легче справиться с помощью Promises.Promises
fetch/xhr
для получения сетевого запроса, но это не влияло на фактическую память. С введением промисов fetch
должна совершать сетевой запрос и возвращать объект Promise, который будет находиться в памяти. Как только запрос выполнится, объект будет заполнен данными из него.
function display(data) { console.log(data); } const futureData = fetch('https//somelink.com'); futureData.then(display); console.log('Me first');
futureData
и в свою очередь передается в качестве параметра (data
) для функции display
. Чтобы понять, как все это работает, рассмотрим, что именно делает fetch
.fetch
– одна из важных функций JS. С ее помощью устанавливается объект Promise
в памяти JS. Он имеет два свойства: value
, в котором хранятся данные ответа, и onFulfilled
, который является пустым массивом.futureData
, которая в свою очередь является объектом promise: futureData.value = response data
onFulfilled[ ]
. Это скрытое свойство объекта Promise
, к которому нельзя получить доступ. Как только свойство value
получает некоторое значение, свойство onFulfilled
автоматически выполняет функцию, которая должна использовать данные из ответа – именно она хранится в массиве onFulfilled
. В приведенном выше фрагменте кода, как только свойство value
получает ответ, запускается функция display
, и данные передаются в качестве аргумента для onFulfilled
.onFulfilled
массиву? Мы не можем использовать array.push()
, так как это скрытое свойство. Вместо этого применим метод then
, что значительно облегчает жизнь.Promise
, вроде неудачного запроса или нулевых данных. Существует множество случаев, когда сетевой запрос может завершиться неудачей. Чтобы решить эту проблему, объект Promise
имеет еще одно скрытое свойство onRejection
, которое является пустым массивом..catch()
, чтобы добавить к нему функцию. Эта функция будет вызвана onRejection
и выполнена в случае, если мы получим ошибку.И напоследок
Promise
, помещается в Microtask Queue.setTimeOut()
), выполняются после выполнения функций объекта Promise
.Заключение
- 2 views
- 0 Comment
Свежие комментарии