Вы когда-нибудь выполняли синхронные вызовы API в Javascript?

Если вы разработчик Javascript, вы должны знать, что Javascript является однопоточным и блокировка основного потока является грехом.
Что произойдет, если вы сделаете синхронный вызов Ajax? jQuery дает нам флаг async, и установка его false сделает запрос Ajax синхронным.

$.ajax({
  url: '<URL>',
  method: 'get',
  async: false, // notice this line
  success: () => {}
});

Синхронный вызов API означает, что поток Javascript остановит дальнейшее выполнение кода до тех пор, пока этот запрос Ajax не будет разрешен. Поскольку основной поток заблокирован в ожидании завершения запроса, ваш браузер перестанет отвечать на события (он перестанет отвечать). Я знаю, о чем вы думаете, с какой стати кому-то это делать?

Допустим, я наивный разработчик и хочу сделать синхронный вызов API. Мне действительно нужны данные API перед рендерингом пользовательского интерфейса, поэтому мне все равно, если моя страница не отвечает в течение 1 или 2 секунд. Однако я хочу показать загрузчик до тех пор, пока не будет разрешен запрос API. Мой код будет выглядеть примерно так:

Вы видите проблему в этом коде?

На первый взгляд все выглядит нормально. Я определил две функции - showLoader и hideLoader для отображения и скрытия элемента загрузчика. Внутри IIFE (немедленно вызываемого функционального выражения) я сначала вызываю функцию showLoader, выполняю синхронный вызов Ajax, а затем вызываю функцию hideLoader. Поскольку вызов API является синхронным, функция hideLoader будет вызываться только после того, как я получу ответ API, поэтому я должен видеть загрузчик в течение этого периода времени.

Единственная проблема в том, что я вообще не вижу загрузчик. Не верите мне? Посмотри сам -

Хм, так что же здесь на самом деле происходит?

Если вы думаете, что это странное поведение связано с вызовом jQuery или Ajax, то вы ошибаетесь! Даже если я имитирую вызов API с помощью цикла, который будет работать в течение 2 секунд, я все равно получу такое же поведение.

Вы в этом разобрались?

Позвольте дать вам подсказку. Если я помещаю цикл (или синхронный вызов Ajax) в функцию setTimeout, я могу видеть начальный загрузчик в течение 2 секунд.

Это результат приведенного выше кода -

Цикл событий в Javascript

Вы, должно быть, уже получили это. Ответ заключается в том, как цикл событий обрабатывает задачу (обратный вызов) и очередь рендеринга.

Всякий раз, когда стек вызовов Javascript пуст, цикл событий будет отслеживать очередь задач, а также очередь рендеринга. Очередь рендеринга имеет наивысший приоритет и используется для рисования пикселей на экране. Он преобразует код HTML, CSS и JS в растровые изображения для показа конечному пользователю. Очередь задач / обратного вызова, с другой стороны, содержит функции обратного вызова (setTimeout, прослушиватели событий, обратные вызовы Ajax и т. Д.), Которые отправляются в стек вызовов (один за другим) циклом событий для выполнения.

Здесь важно отметить, что обе очереди будут обрабатываться только тогда, когда основной стек вызовов пуст. В нашем примере, когда мы не используем setTimeout, код будет выполняться синхронно, а основной поток будет заблокирован. Несмотря на то, что элемент DOM загрузчика изменяется (display: block), цикл обработки событий не получает возможности обработать очередь рендеринга. Когда цикл завершается или вызов API разрешается, свойство CSS загрузчика также изменяется (display: none), поэтому при следующем рендеринге загрузчик по-прежнему невидим.

В последнем случае, когда мы используем setTimeout, весь вызов API (или цикл) помещается в очередь обратного вызова / задачи, а основной поток становится пустым. Это позволяет циклу обработки событий обрабатывать очередь рендеринга (потому что она имеет более высокий приоритет, чем очередь обратного вызова), и, следовательно, загрузчик виден.

Вывод

Javascript - уникальный язык программирования во многих отношениях, и изучение его всегда доставляет удовольствие.

Надеюсь, вам понравилась эта статья :)

использованная литература

  1. Что, черт возьми, за цикл событий? | Филип Робертс | АОонф ЕС
  2. Журнал Франческо Рицци | Основной поток JavaScript. Рассечено .
  3. Задачи, микрозадачи, очереди и расписания