Решаем популярные задачи с асинхронным кодом на JavaScript: часть первая
В статье разобрали популярные задачи с асинхронным кодом, которые могут попасться начинающему Frontend-разработчику на собеседованиях.
16К открытий23К показов
На собеседованиях начинающим Frontend-разработчикам часто попадаются задачи на асинхронный код. Преподаватель Elbrus Bootcamp Денис Образцов выбрал несколько популярных задач, с которыми наши выпускники часто сталкиваются на интервью, и разобрал логику их решения.
В первой части текста вспомним, как устроен цикл событий и разберём несколько базовых задач на логику и внимательность. Во второй части перейдём к более сложным примерам на порядок попадания задач в Event Loop и оптимизацию кода.
Как устроен цикл событий
Машина читает код дважды: сначала в память компьютера записываются переменные, потом происходит непосредственное выполнение кода. Часто задач в коде несколько: они попадают в цикл событий (Event Loop) и выполняются в определённой последовательности.
Последовательность задаётся типом кода: синхронным или асинхронным. В случае с синхронным кодом все задачи попадают сразу в Call Stack и выполняются по очереди.
Асинхронный код используется, например, когда программе нужно обратиться к базе данных или другому внешнему источнику информации. Этот процесс можно сравнить с телефонным звонком: когда вы звоните кому-то, вы заранее не знаете, когда вам ответят — после первого гудка, после пятого или вообще не возьмут трубку.
С асинхронным кодом сложнее: во-первых, он всегда выполняется после синхронного, а во-вторых, делится ещё на две очереди — макро- и микрозадачи.
Микрозадачи — в основном, промисы, которые выполняются в первую очередь. Большие задачи (например, таймеры, AJAX-запросы) попадают в самый конец стека и выполняются последними.
Теперь, когда мы вспомнили теорию, перейдём к разбору задач на понимание асинхронного кода, которые могут попасться на собеседовании. Все задачи рассчитаны на джунов и собраны командой Elbrus Bootcamp на реальных интервью.
Больше задач и историй студентов — в нашем Telegram-канале @Elbrus Bootcamp
Задача первая
Прежде чем разбирать код, рассмотрим пример, к которому мы будем возвращаться на протяжении всей статьи. Он поможет глубже понять принцип работы асинхронного кода.
Представьте, что вы пришли в фастфуд, сделали заказ, получили специальный пульт и ждёте, пока пульт завибрирует и можно будет пойти и забрать заказ.
В первой строке кода мы видим promise — это специальный объект, который даёт обещание, что в будущем будет выполнено то или иное действие. Promise выступает аналогом такого пульта и в данном случае обещает уведомить не о готовности заказа, а об ошибке, если она возникнет.
Под promise прописан вариант развития событий — reject, который выводит в консоль сообщение «Всё сломалось» в случае, если что-то пошло не так. Второй, положительный, вариант resolve в этой задаче не указан.
Вернёмся к примеру с фастфудом: вы сели за столик и ждёте заказ. Через некоторое время пульт завибрировал. Дальше может быть несколько вариантов развития событий: вы успешно получите заказ или кассир позовёт вас сообщить, что какого-то ингредиента нет и блюдо не смогут приготовить. На этот случай и нужны resolve и reject.
Следующий шаг — встать и подойти к стойке. За него отвечают обработчики .catch, которые в коде идут в цепочке друг за другом. Это важный момент: между обработчиками нет точки с запятой, и цепочка идёт сразу после объявления переменной ‘p’, поэтому выполняется только первый .catch. Второй выполняет те же действия и не срабатывает.
Это сравнительно простая задача: в ней нет смешивания синхронного и асинхронного кода. В консоли мы получим результат выполнения promise, а затем — вывод первого .catch.
Дополнение первое
Здесь происходит то же самое, что и в базовом варианте задачи, но с исключениями. Есть два обращения к константе ‘p2’, нет цепочки, между .catch появилась точка с запятой, поэтому в консоль выводится результат обоих обработчиков.
Стоит отметить, что смысла в этом немного: обработчики отлавливают одну и ту же ошибку. Но эта задача скорее на внимательность, чем на логику.
Дополнение второе
В этой версии задачи есть then. Здесь это обработчик положительного результата (resolve), который не выполняет никакую функцию, в этом коде он бесполезен. В тексте задачи по-прежнему упоминается только негативное развитие событий. Поэтому вывод в консоль будет тот же, что и в предыдущей задаче.
Задача два
Разберём текст задачи. В первой строчке указан таймер setTimeout с нулевой задержкой, следом идут два promise: c пустой функцией обработки положительного ответа и без функции.
Здесь then — обработчик первого promise, который получает результат выполнения resolve. В последних строчках — консоль завершения и консоль, которая выводит результат выполнения второго promise.
Вспомним, в каком порядке код попадает в Call Stack. В первую очередь выполняется синхронный код: console.log или promise. По дефолту они не асинхронные, пока вы не сделаете их таковыми (например, добавите .catch или .then).
Таким образом, вывод консоли будет иметь следующий порядок:
Строки с консолями внутри promise выполнятся в первую очередь, поскольку в них нет ничего асинхронного, так как promise сам по себе изначально синхронный. Затем выполняются синхронная консоль ‘End’ и консоль, в которой показывается второй promise, находящийся в стадии ожидания (
Далее выполняется .then. В базовом варианте promise выполняется синхронно. Только после того, как весь синхронный код отработал, выполняется его асинхронный обработчик. В последнюю очередь выполнится макрозадача с setTimeout.
Задача три
В этой задаче первый и последний console.log синхронные, поэтому они выполнятся сразу. Следом идёт promise с двумя обработчиками, которые выстроены в цепочку и выполняются друг за другом. Обратите внимание, что между ними нет точки с запятой. В последнюю очередь выполняется setTimeout, поскольку это макрозадача.
Эти задачи рассчитаны на базовое понимание работы асинхронного кода. В следующей части статьи разберём более сложные кейсы и оптимизируем скорость выполнения задач в Call Stack.
Реклама ООО “Эльбрус Буткемп”
16К открытий23К показов