Однопоточное и синхронное программирование

Если Javascript — ваш первый язык программирования (как для меня), асинхронные функции могут быть трудной концепцией для понимания поначалу. Цель этой статьи — предоставить новичкам концептуальный обзор асинхронного программирования. Есть много статей, посвященных технической части (она может довольно быстро усложниться), ниже я буду рекомендовать статьи, посвященные этому. Я предлагаю вам понять, что такое асинхронное программирование и когда его использовать, прежде чем рассматривать технические аспекты.

По своей природе Javascript — это однопоточный язык программирования, поэтому, когда мы впервые изучаем Javascript, мы обычно пишем синхронный код. Однопоточный означает, что Javascript может обрабатывать только один набор инструкций за раз, а синхронный, по сути, выполняет этот набор инструкций по одной за раз и в том порядке, в котором эти инструкции обрабатываются. Это означает, что если приложение ожидает выполнения набора инструкций, ваше приложение застревает и не может обрабатывать дальнейшие инструкции, пока не будет завершена предыдущая.

Давайте попробуем визуализировать эту концепцию, представьте, что в 7:00 утра по дороге на работу вы заезжаете в местный Макдональдс и выстраиваетесь в очередь в машине. Вы решаете сделать короткую остановку, чтобы выпить черный кофе перед тем, как отправиться на работу. За исключением того, что вы не единственный человек с этой блестящей идеей, есть целая очередь других автомобилей со своими заказами. Кто-то заказывает кофе, кто-то — комплексный завтрак, в любом случае. Вы уже делали это пару сотен раз, так что точно знаете, чего ожидать. Этот типичный утренний опыт разделяет концепции однопоточного и синхронного программирования. Если мы предположим, что клиент считается «обслуженным» только тогда, когда он получил свой заказ, это означает, что одновременно может быть обслужен только один клиент. В переулке для проезда одновременно может обслуживаться только один человек (однопоточный), и они всегда обслуживаются в том порядке, в котором они стояли в очереди. Вы не можете получить свой заказ черного кофе, пока люди перед вами не получат свои заказы (синхронно).

Войдите в асинхронное программирование

Асинхронные функции в Javascript очень эффективны, потому что они позволяют нам устранить узкое место, распространенное в синхронном программировании. Вместо того, чтобы ждать завершения инструкций, прежде чем двигаться дальше, асинхронное программирование позволяет нам продолжать выполнять остальную часть нашего кода, ожидая результата предыдущего набора инструкций.

Чтобы проиллюстрировать это, вернитесь к примеру McDonald’s. Допустим, сегодня утром по какой-то причине было заказано большое количество сэндвичей на завтрак. В результате приходится разбивать больше яиц, ждать, пока яйца приготовятся, ждать, пока пирожки закончат жариться… ну, вы поняли. Пока все это происходит, очередь становится все длиннее и длиннее. Если бы McDonald’s продолжал работать синхронно, среднее время ожидания для каждого клиента ограничивалось бы количеством времени, которое требуется для выполнения заказов на сэндвичи на завтрак. Чтобы снять это ограничение, McDonald’s может реализовать асинхронное действие. Я уверен, что вы видели это раньше, в некоторых McDonald’s есть специально отведенная зона ожидания для заказов, выполнение которых займет некоторое время. Эта зона ожидания — ответ McDonald’s на ловушки синхронных действий. Пока готовится заказ сэндвича на завтрак, клиента просят пройти в специально отведенную зону ожидания, чтобы можно было обслужить клиента, следующего за ним. Независимо от того, получил ли клиент у витрины свой заказ, как только сэндвич для завтрака клиента будет готов, его немедленно обслужат, и он уже в пути. Это простой пример, но он подчеркивает ограничения синхронного программирования и то, как может помочь реализация асинхронных функций.

Javascript может интегрировать асинхронные функции различными способами. Асинхронные обратные вызовы, промисы, асинхронные и ожидающие функции — это инструменты, которыми мы располагаем для реализации асинхронной функциональности. Обратные вызовы — это быстрый способ начать работу, и они действительно хорошо иллюстрируют концепцию. Возьмите эту функцию ниже, я уверен, что она покажется вам знакомой.

Здесь нет ничего особенного, но давайте посмотрим, что произойдет, если мы объявим и вызовем другую функцию после обратного вызова setTimeout.

В этом сценарии, несмотря на то, что setTimeout объявляется и вызывается до вызова функции sayHello, setTimeout выводит на консоль после sayHello. Это показывает, что хотя инструкция setTimeout все еще обрабатывается, мы все еще можем предоставить javascript дальнейшие инструкции (объявление и вызов функции sayHello). По истечении 2500 мс setTimeout выводит «Hello World!!», завершая свой набор инструкций.

Это действительно простая демонстрация того, как работают асинхронные обратные вызовы и что вы можете ожидать от них. Вот — это статья, которую я рекомендую, если вам нужно больше примеров асинхронных обратных вызовов. Как только вы разработаете прочную основу этих концепций, следующее, что вы можете изучить, — это промисы. Обещания — это хлеб с маслом асинхронного программирования в Javascript. Они используются вместе с асинхронными обратными вызовами и функциями async/await. Ниже приведены несколько статей, которые помогут вам начать.

Введение в обещания, а затем метод: https://spring.io/understanding/javascript-promises

Введение в Async и Await: https://medium.com/@zellwk/an-introduction-to-javascripts-async-and-await-edb313356677

Подробное руководство по обещаниям: https://medium.com/@gokulnk/understanding-promises-in-javascript-13d99df067c1

Спасибо за чтение!