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>