Концепция синхронного и асинхронного программирования в JavaScript - Часть 1

При выполнении JS одна из концепций, которая сбивает с толку многих разработчиков от новичков до разработчиков среднего уровня, - это Asynchronous (‘Async’) programming. Поскольку это одна из наиболее распространенных концепций в JavaScript, вам необходимо хорошо ее понять, прежде чем углубляться в JavaScript.

Итак, основываясь на своих исследованиях и выводах, я решил написать статью о Concept of Synchronous & Asynchronous Programming in JavaScript , которая разделена на 3 части, охватывающие следующие концепции соответственно:

  1. Basics of Synchronous and Asynchronous Programming in JavaScript
  2. Callbacks and Promises
  3. Async Await

В этой части мы обсудим первый пункт в списке - Basics of Synchronous and Asynchronous Programming in JavaScript вместе с некоторыми интересными примерами. Я прошу вас, ребята, попрактиковаться в примерах самостоятельно для лучшего понимания.

В общем, синхронный код можно определить как - «набор последовательных операторов». т.е. каждый оператор в коде выполняется один за другим сверху вниз, пока последний оператор не завершит выполнение. Таким образом, каждая инструкция должна ждать завершения выполнения предыдущей.

Давайте попрактикуемся на примере, чтобы визуализировать наше утверждение:

let a = 30
let b = 50
console.log(a)
console.log(b)

Коды выполняются последовательно, и мы получаем следующий результат:

30
50

Давайте перейдем к другому примеру с использованием синхронных функций;

let a = function(){return 20}
let b = function(){return 30}
console.log(a())
console.log(b())

Если мы запустим этот блок кода, мы получим следующий результат:

20
30

То, что я хочу передать, не имеет значения, каким бы сложным он ни был, каждый оператор будет выполняться сверху вниз, то есть sequentially. Функция будет выполнена, затем будет присвоено возвращаемое значение и, наконец, будет выполнена следующая строка. Первый метод может иметь внутри более 1000 строк, но все равно потребуется все время для выполнения операторов внутри него, и тогда будет выполняться только присваивание. И все это до того, как будет выполнена следующая строка. Такова концепция Synchronous Programming, и это то, что JavaScript делает большую часть времени.

Но рассмотрим ситуацию, когда нам нужно получить некоторые данные с сервера, что может занять некоторое время в зависимости от подключения к Интернету, размера данных или любой другой зависимости. Мы не можем просто заморозить пользовательский интерфейс на время выполнения. Это не мгновенно. Вот тут-то и начинается асинхронное программирование.

Давайте рассмотрим пример использования setTimeout(), который является очень простым примером Asynchronous Programming:

let a = 4
let b = 3
setTimeout(function() {
   console.log("Async Task 1")
}, 100)
console.log(a)
setTimeout(function() {
   console.log("Async Task 2")
}, 90)
console.log(b)

Результатом вышеуказанного блока кода будет:

4
3
Async Task 2
Async Task 1

Мы видим, что хотя setTimeout() идет раньше, он печатается в последнюю очередь. Это потому, что для выполнения setTimeout() требуется 100 мсек.

Как Asynchronous метод, он выполняется после выполнения всех синхронных задач, несмотря на положение блоков кода. Таким образом, концепция заключается в том, что если мы используем Asynchronous Programming для выполнения не мгновенных задач, следующей задаче не придется ждать завершения предыдущей для выполнения.

В приведенном выше примере, даже если мы установим время задержки равным 0 ms, мы заметим аналогичное поведение, поскольку Synchronous задачи всегда выполняются перед Asynchronous задачами независимо от позиции. После завершения Synchronous задач, Asynchronous задачи выполняются впоследствии в порядке, соответствующем их времени выполнения. Если вы заметили результат, вы можете увидеть, что Async Task 2 печатается перед Async Task 1, поскольку время задержки второго setTimeout() меньше, чем у первого.

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

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

Приведем последний пример, чтобы прояснить, что я пытаюсь передать.

let a = 1
let b = 2
setTimeout(function() {
   console.log("Async Task a = ", a)
}, 10)
a = 5 // change the value of a after setTimeout()
console.log(a)
console.log(b)

Если вы запустите этот блок кода, на выходе мы получим следующее:

5
2
Async Task a = 5

Как видите, даже если a присвоено другое значение после setTimeout(), результат setTimeout() будет Async Task a = 5. Это связано с тем, что, как мы обсуждали ранее, setTimeout() являясь Asynchronous функцией по умолчанию, она выполняется после того, как все остальные Synchronous задачи выполняются последовательно, независимо от установленного времени. То есть, даже если мы установим время задержки на0ms, мы будем наблюдать такое же поведение. Итак, переменная a уже установлена ​​в 5 перед выполнением setTimeout(), в результате чего будет получен вышеуказанный результат.

Наконец, мы можем заключить, что Asynchronous Programming упрощает обработку более чем одной задачи за раз и позволяет выразить ожидание длительных действий без зависания программы во время этих действий.

На этом пока все. Надеюсь, вам стало легче понять основную концепцию. Мы высоко ценим любые предложения по этой статье, так как это моя первая статья.
Следующая часть этой статьи посвящена обратным вызовам и обещаниям, которые упростили асинхронное программирование. Щелкните здесь, чтобы перейти к следующей части этой статьи: Часть 2