HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-02-21
1 <p><a>#статьи</a></p>
1 <p><a>#статьи</a></p>
2 <ul><li>23 янв 2019</li>
2 <ul><li>23 янв 2019</li>
3 <li>0</li>
3 <li>0</li>
4 </ul><p>Event loop (событийные циклы) - важная часть архитектуры JavaScript. Мы попросили эксперта объяснить, как в этом разобраться.</p>
4 </ul><p>Event loop (событийные циклы) - важная часть архитектуры JavaScript. Мы попросили эксперта объяснить, как в этом разобраться.</p>
5 <p> vlada_maestro / shutterstock</p>
5 <p> vlada_maestro / shutterstock</p>
6 <p>Автор в сфере IT, digital, экономики и финансов. Ведёт некоммерческий проект для начинающих писателей "ЛитЦех".</p>
6 <p>Автор в сфере IT, digital, экономики и финансов. Ведёт некоммерческий проект для начинающих писателей "ЛитЦех".</p>
7 <p>Понимание работы event loop - неотъемлемый пункт карьерного роста middle-разработчика.</p>
7 <p>Понимание работы event loop - неотъемлемый пункт карьерного роста middle-разработчика.</p>
8 <p>А сейчас о событийных циклах рассказывает Александр Кузьмин - ведущий программист с десятилетним опытом во frontend, руководитель отдела клиентской разработки компании<a>IT-Park</a>. Передаём слово эксперту.</p>
8 <p>А сейчас о событийных циклах рассказывает Александр Кузьмин - ведущий программист с десятилетним опытом во frontend, руководитель отдела клиентской разработки компании<a>IT-Park</a>. Передаём слово эксперту.</p>
9 <p>У каждого языка свой подход к параллельному вычислению данных. Например, в языках типа C++ оно передаётся в отдельный поток или даже процесс, который выполняется на другой машине.</p>
9 <p>У каждого языка свой подход к параллельному вычислению данных. Например, в языках типа C++ оно передаётся в отдельный поток или даже процесс, который выполняется на другой машине.</p>
10 <p><strong>Александр Кузьмин</strong></p>
10 <p><strong>Александр Кузьмин</strong></p>
11 <p>ведущий программист, руководитель отдела клиентской разработки компании<a>IT-Park</a></p>
11 <p>ведущий программист, руководитель отдела клиентской разработки компании<a>IT-Park</a></p>
12 <p>Если нужно сообщить потоку что-то вроде "посчитай вот это и положи результат в базу данных, а я когда-нибудь приду за ними", мы имеем дело с асинхронными операциями.</p>
12 <p>Если нужно сообщить потоку что-то вроде "посчитай вот это и положи результат в базу данных, а я когда-нибудь приду за ними", мы имеем дело с асинхронными операциями.</p>
13 <p>Это значит, что код, который их вызвал, не ждёт завершения выполнения, а продолжает исполняться дальше. Если же мы хотим дождаться результата, у многих современных языков есть операторы<em>async</em>и <em>await</em>для синхронизации исполняемого кода.</p>
13 <p>Это значит, что код, который их вызвал, не ждёт завершения выполнения, а продолжает исполняться дальше. Если же мы хотим дождаться результата, у многих современных языков есть операторы<em>async</em>и <em>await</em>для синхронизации исполняемого кода.</p>
14 <p>В JavaScript асинхронность - основной инструмент. Во времена до появления Node.JS он был практически единственным языком исполнения сценариев на клиенте в вебе<em>(Internet Explorer поддерживал VB Script, но его никто не использовал)</em>. Сейчас невозможно представить интернет, где все запросы на сервер отправлялись бы с перезагрузкой страницы. Напротив, мы пришли к одностраничному вебу, в котором на стороне клиента происходит разрешение адресов страниц и отображение соответствующего контента.</p>
14 <p>В JavaScript асинхронность - основной инструмент. Во времена до появления Node.JS он был практически единственным языком исполнения сценариев на клиенте в вебе<em>(Internet Explorer поддерживал VB Script, но его никто не использовал)</em>. Сейчас невозможно представить интернет, где все запросы на сервер отправлялись бы с перезагрузкой страницы. Напротив, мы пришли к одностраничному вебу, в котором на стороне клиента происходит разрешение адресов страниц и отображение соответствующего контента.</p>
15 <p>Любые данные от сервера запрашиваются асинхронно: отправляется запрос (XMLHttpRequest или XHR), и код не ждёт его возвращения, продолжая выполняться. Когда же сервер отвечает, объект XHR получает уведомление об этом и запускает функцию обратного вызова - callback, который передали в него перед отправкой запроса.</p>
15 <p>Любые данные от сервера запрашиваются асинхронно: отправляется запрос (XMLHttpRequest или XHR), и код не ждёт его возвращения, продолжая выполняться. Когда же сервер отвечает, объект XHR получает уведомление об этом и запускает функцию обратного вызова - callback, который передали в него перед отправкой запроса.</p>
16 <p>Если придётся ждать, пока запрос придёт, JavaScript перестанет принимать любые события, а страница зависнет. Чтобы пользователь спокойно использовал веб-приложение, запрос выводят из текущего контекста выполнения. Операции, результата которых приходится ждать, прежде чем продолжать выполнение кода, называются блокирующими. О них - во <a>второй части</a>статьи.</p>
16 <p>Если придётся ждать, пока запрос придёт, JavaScript перестанет принимать любые события, а страница зависнет. Чтобы пользователь спокойно использовал веб-приложение, запрос выводят из текущего контекста выполнения. Операции, результата которых приходится ждать, прежде чем продолжать выполнение кода, называются блокирующими. О них - во <a>второй части</a>статьи.</p>
17 <p>Суть кроется в устройстве языка:</p>
17 <p>Суть кроется в устройстве языка:</p>
18 <p>Если правильно использовать инструменты языка, то выполнение кода, которое происходит последовательно и в одном потоке, никак не мешает приёму событий и реакции на них - человек спокойно работает с интерфейсом, не замечая лагов, сбоев и зависаний.</p>
18 <p>Если правильно использовать инструменты языка, то выполнение кода, которое происходит последовательно и в одном потоке, никак не мешает приёму событий и реакции на них - человек спокойно работает с интерфейсом, не замечая лагов, сбоев и зависаний.</p>
19 <p>Чтобы этот хитрый процесс слаженно работал, в JavaScript реализован механизм для управления очерёдностью исполнения кода. Поскольку это однопоточный язык, возникла необходимость "вклиниваться" в текущий контекст исполнения. Этот механизм называется event loop - событийный цикл.</p>
19 <p>Чтобы этот хитрый процесс слаженно работал, в JavaScript реализован механизм для управления очерёдностью исполнения кода. Поскольку это однопоточный язык, возникла необходимость "вклиниваться" в текущий контекст исполнения. Этот механизм называется event loop - событийный цикл.</p>
20 <p>С английского loop переводится как "петля", что отлично отражает смысл: мы имеем дело с закольцованной очередью.</p>
20 <p>С английского loop переводится как "петля", что отлично отражает смысл: мы имеем дело с закольцованной очередью.</p>
21 <p>Event loop регулирует последовательность исполнения контекстов - стек. Он формируется, когда сработало событие или была вызвана функция. Реакция на событие помещается в очередь исполнения, в event loop, который последовательно, с каждым циклом выполняет попадающий в него код. При этом привязанная к событию функция вызывается следующей после текущего контекста исполнения.</p>
21 <p>Event loop регулирует последовательность исполнения контекстов - стек. Он формируется, когда сработало событие или была вызвана функция. Реакция на событие помещается в очередь исполнения, в event loop, который последовательно, с каждым циклом выполняет попадающий в него код. При этом привязанная к событию функция вызывается следующей после текущего контекста исполнения.</p>
22 <p>В JavaScript постоянно работают связанные между собой синхронная и асинхронная очереди выполнения. Синхронная - стек - формирует очередь и пробрасывает в асинхронную - event loop - вызовы функций, которые будут выполнены после текущего запланированного исполняемого контекста.</p>
22 <p>В JavaScript постоянно работают связанные между собой синхронная и асинхронная очереди выполнения. Синхронная - стек - формирует очередь и пробрасывает в асинхронную - event loop - вызовы функций, которые будут выполнены после текущего запланированного исполняемого контекста.</p>
23 <p>Чтобы данные находились в консистентном состоянии, каждая функция должна быть выполнена до конца. Это обусловлено однопоточностью JavaScript и некоторыми другими особенностями, например характерными для функциональных языков программирования замыканиями. Поэтому единственный поток представлен в виде очереди контекстов исполнения, в которой и происходит "вклинивание" функций, прошедших через цикл событий.</p>
23 <p>Чтобы данные находились в консистентном состоянии, каждая функция должна быть выполнена до конца. Это обусловлено однопоточностью JavaScript и некоторыми другими особенностями, например характерными для функциональных языков программирования замыканиями. Поэтому единственный поток представлен в виде очереди контекстов исполнения, в которой и происходит "вклинивание" функций, прошедших через цикл событий.</p>
24 Схема цикла событий. На каждом этапе проверяется одна из его очередей. Несмотря на названия,<em>setImmediate</em>выполняется внутри цикла каждую итерацию<em>(tick),</em>а <em>nextTick</em>вызывается в момент срабатывания - между этапами цикла.<p><strong>В JavaScript существует понятие "контекст функции". Но есть и другой термин - "контекст исполнения". Это тело функции со всеми переменными и другими функциями, которое называют "область видимости", с английского - "scope". Важно не путать понятия, это принципиально разные вещи.</strong></p>
24 Схема цикла событий. На каждом этапе проверяется одна из его очередей. Несмотря на названия,<em>setImmediate</em>выполняется внутри цикла каждую итерацию<em>(tick),</em>а <em>nextTick</em>вызывается в момент срабатывания - между этапами цикла.<p><strong>В JavaScript существует понятие "контекст функции". Но есть и другой термин - "контекст исполнения". Это тело функции со всеми переменными и другими функциями, которое называют "область видимости", с английского - "scope". Важно не путать понятия, это принципиально разные вещи.</strong></p>
25 <p>JavaScript - интерпретируемый язык. Это значит, что любой код проходит через интерпретатор, который исполняет его построчно. Но и здесь есть нюансы.</p>
25 <p>JavaScript - интерпретируемый язык. Это значит, что любой код проходит через интерпретатор, который исполняет его построчно. Но и здесь есть нюансы.</p>
26 <p>Как только скрипт попадает в интерпретатор, формируются глобальный контекст и глобальная область видимости, в которой держится Variable Object, или VO - объект переменных.</p>
26 <p>Как только скрипт попадает в интерпретатор, формируются глобальный контекст и глобальная область видимости, в которой держится Variable Object, или VO - объект переменных.</p>
27 <p>Он формируется из переменных вида Function Declaration и атрибутов функции по следующему принципу. Интерпретатор считывает код и находит все объявления:</p>
27 <p>Он формируется из переменных вида Function Declaration и атрибутов функции по следующему принципу. Интерпретатор считывает код и находит все объявления:</p>
28 <ul><li>переменных по ключевому слову<em>var</em>(<em>const</em>или<em>let</em>в ES6 и выше);</li>
28 <ul><li>переменных по ключевому слову<em>var</em>(<em>const</em>или<em>let</em>в ES6 и выше);</li>
29 <li>функций, объявленных ключевым словом<em>function</em>, без присваивания.</li>
29 <li>функций, объявленных ключевым словом<em>function</em>, без присваивания.</li>
30 </ul><p>Это складывается в VO текущего контекста исполнения. Затем берётся<em>Variable Object</em>внешней области видимости и к нему добавляется сформированный выше VO. Сверху он дополняется параметрами функции и их значениями на момент исполнения.</p>
30 </ul><p>Это складывается в VO текущего контекста исполнения. Затем берётся<em>Variable Object</em>внешней области видимости и к нему добавляется сформированный выше VO. Сверху он дополняется параметрами функции и их значениями на момент исполнения.</p>
31 <p>При этом нет разницы, в каком месте функции они определяются. Переменная может быть определена в любой части кода, как и функция.</p>
31 <p>При этом нет разницы, в каком месте функции они определяются. Переменная может быть определена в любой части кода, как и функция.</p>
32 <p>Рассмотрим скрипт:</p>
32 <p>Рассмотрим скрипт:</p>
33 var a = 10; var c = 7; function func(a, b, d) { console.log(a, b, c, d); c = a + d; } var b = 3; func(10, a, b); console.log(c);<p>VO этого скрипта формируется:</p>
33 var a = 10; var c = 7; function func(a, b, d) { console.log(a, b, c, d); c = a + d; } var b = 3; func(10, a, b); console.log(c);<p>VO этого скрипта формируется:</p>
34 <ol><li>Из переменной<em>a</em>, значение которой -<em>undefined</em>.</li>
34 <ol><li>Из переменной<em>a</em>, значение которой -<em>undefined</em>.</li>
35 <li>Переменной<em>c</em>, значение которой -<em>undefined</em>.</li>
35 <li>Переменной<em>c</em>, значение которой -<em>undefined</em>.</li>
36 <li>Переменной<em>b</em>, значение которой -<em>undefined</em>.</li>
36 <li>Переменной<em>b</em>, значение которой -<em>undefined</em>.</li>
37 <li>Функции<em>func</em>с соответствующим телом.</li>
37 <li>Функции<em>func</em>с соответствующим телом.</li>
38 </ol><p>Затем скрипт начнет исполняться по следующему сценарию:</p>
38 </ol><p>Затем скрипт начнет исполняться по следующему сценарию:</p>
39 <ol><li>В переменную<em>a</em>запишется значение<em>10</em>.</li>
39 <ol><li>В переменную<em>a</em>запишется значение<em>10</em>.</li>
40 <li>В переменную<em>c</em>запишется значение<em>7</em>.</li>
40 <li>В переменную<em>c</em>запишется значение<em>7</em>.</li>
41 <li>В переменную<em>b</em>запишется значение<em>3</em>.</li>
41 <li>В переменную<em>b</em>запишется значение<em>3</em>.</li>
42 <li>Будет вызвана функция<em>func</em>.</li>
42 <li>Будет вызвана функция<em>func</em>.</li>
43 <li>Создается контекст исполнения функции<em>func</em>.</li>
43 <li>Создается контекст исполнения функции<em>func</em>.</li>
44 <li>В VO контекста исполнения функции<em>func</em>будут записаны переменные из внешней области видимости:<em>a, c </em>и<em>b, c</em>присвоенными значениями.</li>
44 <li>В VO контекста исполнения функции<em>func</em>будут записаны переменные из внешней области видимости:<em>a, c </em>и<em>b, c</em>присвоенными значениями.</li>
45 <li>В VO контекста исполнения функции<em>func</em>будут созданы переменные из списка аргументов; поскольку переменные<em>a</em>и<em>b</em>уже существуют в VO, добавлена будет только переменная<em>d</em>со значением<em>undefined</em>.</li>
45 <li>В VO контекста исполнения функции<em>func</em>будут созданы переменные из списка аргументов; поскольку переменные<em>a</em>и<em>b</em>уже существуют в VO, добавлена будет только переменная<em>d</em>со значением<em>undefined</em>.</li>
46 <li>В переменную<em>a</em>VO контекста исполнения функции<em>func</em>будет записано значение<em>10</em>.</li>
46 <li>В переменную<em>a</em>VO контекста исполнения функции<em>func</em>будет записано значение<em>10</em>.</li>
47 <li>В переменную<em>b</em>VO контекста исполнения функции<em>func</em>будет записано значение переменной<em>a</em>внешней области видимости -<em>10</em>.</li>
47 <li>В переменную<em>b</em>VO контекста исполнения функции<em>func</em>будет записано значение переменной<em>a</em>внешней области видимости -<em>10</em>.</li>
48 <li>В переменную<em>d</em>VO контекста исполнения функции<em>func</em>будет записано значение переменной<em>b</em>внешней области видимости -<em>3</em>.</li>
48 <li>В переменную<em>d</em>VO контекста исполнения функции<em>func</em>будет записано значение переменной<em>b</em>внешней области видимости -<em>3</em>.</li>
49 <li>Контекст исполнения функции<em>func</em>будет запущен.</li>
49 <li>Контекст исполнения функции<em>func</em>будет запущен.</li>
50 <li>В консоль выведется<em>1010 7 3</em>.</li>
50 <li>В консоль выведется<em>1010 7 3</em>.</li>
51 <li>В переменную c, находящуюся во внешней области видимости, будет записано значение<em>13</em>.</li>
51 <li>В переменную c, находящуюся во внешней области видимости, будет записано значение<em>13</em>.</li>
52 <li>Контекст выполнения функции<em>func</em>будет завершён; VO функции<em>func</em>будет удалён.</li>
52 <li>Контекст выполнения функции<em>func</em>будет завершён; VO функции<em>func</em>будет удалён.</li>
53 <li>В консоль выведется<em>13</em>.</li>
53 <li>В консоль выведется<em>13</em>.</li>
54 </ol><p>Теперь перепишем скрипт, добавив<em>setTimeout</em>с нулевым тайм-аутом у вызова функции:</p>
54 </ol><p>Теперь перепишем скрипт, добавив<em>setTimeout</em>с нулевым тайм-аутом у вызова функции:</p>
55 var a = 10; var c = 7; function func(a, b, d) { console.log(a, b, c, d); c = a + d; } var b = 3; setTimeout(function () { func(10, a, b); }, 0); console.log(c);<p>На первый взгляд может показаться, что ничего не изменится и функция func будет выполнена без задержки. Но это не так. На самом деле произойдёт следующее:</p>
55 var a = 10; var c = 7; function func(a, b, d) { console.log(a, b, c, d); c = a + d; } var b = 3; setTimeout(function () { func(10, a, b); }, 0); console.log(c);<p>На первый взгляд может показаться, что ничего не изменится и функция func будет выполнена без задержки. Но это не так. На самом деле произойдёт следующее:</p>
56 <ol><li>В переменную<em>a</em>запишется значение<em>10</em>.</li>
56 <ol><li>В переменную<em>a</em>запишется значение<em>10</em>.</li>
57 <li>В переменную<em>c</em>запишется значение<em>7</em>.</li>
57 <li>В переменную<em>c</em>запишется значение<em>7</em>.</li>
58 <li>В переменную<em>b</em>запишется значение<em>3</em>.</li>
58 <li>В переменную<em>b</em>запишется значение<em>3</em>.</li>
59 <li>Функция<em>func</em>попадает в пул ожидания.</li>
59 <li>Функция<em>func</em>попадает в пул ожидания.</li>
60 <li>Создаётся контекст исполнения функции<em>func</em>.</li>
60 <li>Создаётся контекст исполнения функции<em>func</em>.</li>
61 <li>По истечении<em>0</em>миллисекунд контекст исполнения функции<em>func</em>будет помещён в <em>event loop</em>.</li>
61 <li>По истечении<em>0</em>миллисекунд контекст исполнения функции<em>func</em>будет помещён в <em>event loop</em>.</li>
62 <li>В консоль выведется<em>7</em>.</li>
62 <li>В консоль выведется<em>7</em>.</li>
63 <li>В VO контекста исполнения функции<em>func</em>будут записаны переменные из внешней области видимости:<em>a, c </em>и<em>b, c</em>присвоенными значениями.</li>
63 <li>В VO контекста исполнения функции<em>func</em>будут записаны переменные из внешней области видимости:<em>a, c </em>и<em>b, c</em>присвоенными значениями.</li>
64 <li>В VO контекста исполнения функции<em>func</em>будут созданы переменные из списка аргументов; поскольку переменные<em>a</em>и<em>b</em>уже существуют в VO, добавлена будет только переменная<em>d</em>со значением<em>undefined</em>.</li>
64 <li>В VO контекста исполнения функции<em>func</em>будут созданы переменные из списка аргументов; поскольку переменные<em>a</em>и<em>b</em>уже существуют в VO, добавлена будет только переменная<em>d</em>со значением<em>undefined</em>.</li>
65 <li>В переменную a VO контекста исполнения функции<em>func</em>будет записано значение<em>10</em>.</li>
65 <li>В переменную a VO контекста исполнения функции<em>func</em>будет записано значение<em>10</em>.</li>
66 <li>В переменную<em>b</em>VO контекста исполнения функции<em>func</em>будет записано значение переменной<em>a</em>внешней области видимости -<em>10</em>.</li>
66 <li>В переменную<em>b</em>VO контекста исполнения функции<em>func</em>будет записано значение переменной<em>a</em>внешней области видимости -<em>10</em>.</li>
67 <li>В переменную<em>d</em>VO контекста исполнения функции<em>func</em>будет записано значение переменной<em>b</em>внешней области видимости -<em>3</em>.</li>
67 <li>В переменную<em>d</em>VO контекста исполнения функции<em>func</em>будет записано значение переменной<em>b</em>внешней области видимости -<em>3</em>.</li>
68 <li>Контекст исполнения функции<em>func</em>будет запущен.</li>
68 <li>Контекст исполнения функции<em>func</em>будет запущен.</li>
69 <li>В консоль выведется<em>1010 7 3</em>.</li>
69 <li>В консоль выведется<em>1010 7 3</em>.</li>
70 <li>В переменную c, находящуюся во внешней области видимости, будет записано значение<em>13</em>.</li>
70 <li>В переменную c, находящуюся во внешней области видимости, будет записано значение<em>13</em>.</li>
71 <li>Контекст выполнения функции<em>func</em>будет завершён; VO функции<em>func</em>будет удалён.</li>
71 <li>Контекст выполнения функции<em>func</em>будет завершён; VO функции<em>func</em>будет удалён.</li>
72 </ol><p>Всему виной<em>setTimeout</em>, очевидно. Он выводит контекст исполнения функции из синхронного потока, помещая его в <em>event loop</em>. То же самое происходит и с регистрацией событий. Мы можем подписаться на событие при помощи функции<em>addEventListener</em>. Передавая функцию обратного вызова -<em>callback</em>, добавляем её в список функций, которые должны быть вызваны при срабатывании этого события.</p>
72 </ol><p>Всему виной<em>setTimeout</em>, очевидно. Он выводит контекст исполнения функции из синхронного потока, помещая его в <em>event loop</em>. То же самое происходит и с регистрацией событий. Мы можем подписаться на событие при помощи функции<em>addEventListener</em>. Передавая функцию обратного вызова -<em>callback</em>, добавляем её в список функций, которые должны быть вызваны при срабатывании этого события.</p>
73 <p>Допустим, мы хотим нажатием на кнопку перекрасить её в красный цвет. Код, который это выполняет, выглядит так:</p>
73 <p>Допустим, мы хотим нажатием на кнопку перекрасить её в красный цвет. Код, который это выполняет, выглядит так:</p>
74 var button = document.querySelector(‘button’); button.addEventListener(‘click’, function (evt) { button.style.background = ‘#f00’; });<p>Переданная функция всегда выполняется через<em>event loop</em>. При возникновении события в цикл последовательно попадут все привязанные к нему функции. Для каждой будет формироваться контекст исполнения, который будет запущен следом за текущим.</p>
74 var button = document.querySelector(‘button’); button.addEventListener(‘click’, function (evt) { button.style.background = ‘#f00’; });<p>Переданная функция всегда выполняется через<em>event loop</em>. При возникновении события в цикл последовательно попадут все привязанные к нему функции. Для каждой будет формироваться контекст исполнения, который будет запущен следом за текущим.</p>
75 <p>Если в процессе будет вызвано ещё одно событие, его коллбэки будут вставать в очередь по тому же принципу, возможно, перемежаясь с контекстами исполнения первого события.</p>
75 <p>Если в процессе будет вызвано ещё одно событие, его коллбэки будут вставать в очередь по тому же принципу, возможно, перемежаясь с контекстами исполнения первого события.</p>
76 <p>Более сложный пример: есть две кнопки, первая перекрашивает фон страницы в красный цвет, а вторая - в жёлтый, но у второй перекрашивание фона завёрнуто в <em>setTimeout</em>с нулевой задержкой. И мы вручную вызываем событие нажатия сначала на жёлтую кнопку, а потом - на красную.</p>
76 <p>Более сложный пример: есть две кнопки, первая перекрашивает фон страницы в красный цвет, а вторая - в жёлтый, но у второй перекрашивание фона завёрнуто в <em>setTimeout</em>с нулевой задержкой. И мы вручную вызываем событие нажатия сначала на жёлтую кнопку, а потом - на красную.</p>
77 var redButton = document.getElementById(‘red’); redButton.addEventListener(‘click’, function () { document.body.style.background = ‘#f00’; }); var yellowButton = document.getElementById(‘yellow’) yellowButton.addEventListener(‘click’, function () { setTimeout(function () { document.body.style.background = ‘#ff0’; }, 0); }); yellowButton.click(); redButton.click();<p>Живой пример:</p>
77 var redButton = document.getElementById(‘red’); redButton.addEventListener(‘click’, function () { document.body.style.background = ‘#f00’; }); var yellowButton = document.getElementById(‘yellow’) yellowButton.addEventListener(‘click’, function () { setTimeout(function () { document.body.style.background = ‘#ff0’; }, 0); }); yellowButton.click(); redButton.click();<p>Живой пример:</p>
78 <p>Что происходит в такой ситуации, исходя из того, что мы рассмотрели выше?</p>
78 <p>Что происходит в такой ситуации, исходя из того, что мы рассмотрели выше?</p>
79 <ol><li>Вызывается событие<em>click</em>на жёлтой кнопке.</li>
79 <ol><li>Вызывается событие<em>click</em>на жёлтой кнопке.</li>
80 <li>Формируется контекст исполнения для коллбэка жёлтой кнопки.</li>
80 <li>Формируется контекст исполнения для коллбэка жёлтой кнопки.</li>
81 <li>Вызывается контекст исполнения для жёлтой кнопки.</li>
81 <li>Вызывается контекст исполнения для жёлтой кнопки.</li>
82 <li>Контекст исполнения коллбэка<em>setTimeout</em>помещается в <em>event loop</em>.</li>
82 <li>Контекст исполнения коллбэка<em>setTimeout</em>помещается в <em>event loop</em>.</li>
83 <li>Вызывается событие<em>click</em>на красной кнопке.</li>
83 <li>Вызывается событие<em>click</em>на красной кнопке.</li>
84 <li>Формируется контекст исполнения для коллбэка красной кнопки.</li>
84 <li>Формируется контекст исполнения для коллбэка красной кнопки.</li>
85 <li>Вызывается контекст исполнения для красной кнопки.</li>
85 <li>Вызывается контекст исполнения для красной кнопки.</li>
86 <li>Фону страницы дается значение<em>"#f00"</em>.</li>
86 <li>Фону страницы дается значение<em>"#f00"</em>.</li>
87 <li>Вызывается событие<em>repaint</em>для DOM.</li>
87 <li>Вызывается событие<em>repaint</em>для DOM.</li>
88 <li>Фон страницы становится красным.</li>
88 <li>Фон страницы становится красным.</li>
89 <li>Вызывается контекст исполнения коллбэка<em>setTimeout</em>.</li>
89 <li>Вызывается контекст исполнения коллбэка<em>setTimeout</em>.</li>
90 <li>Фону страницы назначается значение<em>"#ff0".</em></li>
90 <li>Фону страницы назначается значение<em>"#ff0".</em></li>
91 <li>Вызывается событие<em>repaint</em>для DOM.</li>
91 <li>Вызывается событие<em>repaint</em>для DOM.</li>
92 <li>Фон страницы становится жёлтым.</li>
92 <li>Фон страницы становится жёлтым.</li>
93 </ol><p>Обратите внимание, что исполнение коллбэков событий<em>click</em>на кнопках при вызове из кода происходит сразу же, не попадая в event loop:<em>setTimeout</em>с нулевой задержкой отложил перекраску фона в жёлтый, но функция сама была исполнена в момент вызова.</p>
93 </ol><p>Обратите внимание, что исполнение коллбэков событий<em>click</em>на кнопках при вызове из кода происходит сразу же, не попадая в event loop:<em>setTimeout</em>с нулевой задержкой отложил перекраску фона в жёлтый, но функция сама была исполнена в момент вызова.</p>
94 <p>Это происходит из-за того, что события из кода не требуется выполнять асинхронно. Действительно, в такой ситуации мы находимся в предсказуемом окружении, тогда как пользовательские события могут случаться в любой момент.</p>
94 <p>Это происходит из-за того, что события из кода не требуется выполнять асинхронно. Действительно, в такой ситуации мы находимся в предсказуемом окружении, тогда как пользовательские события могут случаться в любой момент.</p>
95 <p>Это приводит к теме<a>следующей</a>части: об управлении событийным циклом и тем, что будет в него попадать. Подробно рассмотрим, как грамотно формировать цепочки последовательных асинхронно вызванных контекстов вызова, уменьшая вычислительную сложность каждого из них, освобождая поток и позволяя пользовательским событиям "вклиниваться" в очередь исполнения.</p>
95 <p>Это приводит к теме<a>следующей</a>части: об управлении событийным циклом и тем, что будет в него попадать. Подробно рассмотрим, как грамотно формировать цепочки последовательных асинхронно вызванных контекстов вызова, уменьшая вычислительную сложность каждого из них, освобождая поток и позволяя пользовательским событиям "вклиниваться" в очередь исполнения.</p>
96 <a>Научитесь: Профессия Фронтенд-разработчик + ИИ Узнать больше</a>
96 <a>Научитесь: Профессия Фронтенд-разработчик + ИИ Узнать больше</a>