aboutsummaryrefslogtreecommitdiff
path: root/files/ru/web/javascript/eventloop/index.html
diff options
context:
space:
mode:
Diffstat (limited to 'files/ru/web/javascript/eventloop/index.html')
-rw-r--r--files/ru/web/javascript/eventloop/index.html111
1 files changed, 111 insertions, 0 deletions
diff --git a/files/ru/web/javascript/eventloop/index.html b/files/ru/web/javascript/eventloop/index.html
new file mode 100644
index 0000000000..c0becda6c8
--- /dev/null
+++ b/files/ru/web/javascript/eventloop/index.html
@@ -0,0 +1,111 @@
+---
+title: Параллельная модель и цикл событий.
+slug: Web/JavaScript/EventLoop
+tags:
+ - Руководство
+translation_of: Web/JavaScript/EventLoop
+---
+<p>{{JsSidebar("Advanced")}}</p>
+
+<p>Параллелизм/Многопоточность в JavaScript работает за счёт цикла событий (<strong>event loop</strong>), который отвечает за выполнение кода, сбора и обработки событий и выполнения под-задач из очереди (<strong>queued sub-tasks</strong>). Эта модель весьма отличается от других языков программирования, таких как C и Java.</p>
+
+<h2 id="Концепция_жизненного_цикла">Концепция жизненного цикла</h2>
+
+<p>В следующей секции объясняется теоретическая модель. Современные JavaScript движки внедряют/имплементируют и существенно оптимизируют этот процесс.</p>
+
+<h3 id="Визуальное_представление">Визуальное представление</h3>
+
+<p style="text-align: center;"><img alt="Stack, heap, queue" src="/files/4617/default.svg" style="height: 270px; width: 294px;"></p>
+
+<p style="text-align: center;">Для лучшего <strong>визуального</strong> представления работы <strong>Event loop</strong>, Вы можете ознакомиться с данным видео: <a href="https://www.youtube.com/watch?v=8aGhZQkoFbQ&amp;t=389s">https://www.youtube.com/watch?v=8aGhZQkoFbQ&amp;t=389s</a></p>
+
+<h3 id="Стек">Стек</h3>
+
+<p>Вызов любой функции создает контекст выполнения (<a href="https://wiki.developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide/In_depth#JavaScript_execution_contexts">Execution Context</a>). При вызове вложенной функции создается новый контекст, а старый сохраняется в специальной структуре данных - стеке вызовов (Call Stack).</p>
+
+<pre class="brush: js">function f(b) {
+ var a = 12;
+ return a + b + 35;
+}
+
+function g(x) {
+ var m = 4;
+ return f(m * x);
+}
+
+g(21);
+</pre>
+
+<p>Когда вызывается функция <code>g</code>,  создаётся первый контекст выполнения, содержащий аргументы функции <code>g</code> и локальные переменные. Когда <code>g</code> вызывает <code>f</code>, создаётся второй контекст с аргументами <code>f</code> и её локальными переменными.  И этот контекст выполнения <code>f</code> помещается в стек вызовов выше первого. Когда <code>f</code> возвращает результат, верхний элемент из стека удаляется. Когда <code>g</code> возвращает результат, ее контекст также удалится, и стек становится пустым.</p>
+
+<h3 id="Куча">Куча</h3>
+
+<p>Объекты размещаются в <a href="https://ru.wikipedia.org/wiki/%D0%9A%D1%83%D1%87%D0%B0_(%D0%BF%D0%B0%D0%BC%D1%8F%D1%82%D1%8C)">куче</a>. Куча — это просто имя для обозначения большой неструктурированной области памяти.</p>
+
+<h3 id="Очередь">Очередь</h3>
+
+<p>Среда выполнения JavaScript содержит очередь задач. Эта очередь — список задач, подлежащих обработке. Каждая задача ассоциируется с некоторой функцией, которая будет вызвана, чтобы обработать эту задачу.</p>
+
+<p>Когда стек полностью освобождается, самая первая задача извлекается из очереди и обрабатывается. Обработка задачи состоит в вызове  ассоциированной с ней функции с параметрами, записанными в этой задаче. Как обычно, вызов функции создаёт новый контекст выполнения и заносится в стек вызовов.</p>
+
+<p>Обработка задачи заканчивается, когда стек снова становится пустым. Следующая задача извлекается из очереди и начинается её обработка.</p>
+
+<h2 id="Цикл_событий">Цикл событий</h2>
+
+<p>Модель событийного цикла (<code>event loop</code>) называется так потому, что отслеживает новые события в цикле:</p>
+
+<pre class="brush: js">while(queue.waitForMessage()){
+ queue.processNextMessage();
+}</pre>
+
+<p><code>queue.waitForMessage</code> ожидает поступления задач, если очередь пуста.</p>
+
+<h3 id="Запуск_до_завершения">Запуск до завершения</h3>
+
+<p>Каждая задача выполняется полностью, прежде чем начнет обрабатываться следующая. Благодаря этому мы точно знаем: когда выполняется текущая функция – она не может быть приостановлена и будет целиком завершена до начала выполнения другого кода (который может изменить данные, с которыми работает текущая функция). Это отличает JavaScript от такого языка программирования как C. Поскольку в С функция, запущенная в отдельном потоке, в любой момент может быть остановлена, чтобы выполнить какой-то другой код в другом потоке.</p>
+
+<p>У данного подхода есть и минусы. Если задача занимает слишком много времени, то веб-приложение не может обрабатывать действия пользователя в это время (например, скролл или клик). Браузер старается смягчить проблему и выводит сообщение <em>"скрипт выполняется слишком долго" ("a script is taking too long to run")</em> и предлагает остановить его. Хорошей практикой является создание задач, которые исполняются быстро, и если возможно, разбиение одной задачи на несколько мелких.</p>
+
+<h3 id="Добавление_событий_в_очередь">Добавление событий в очередь</h3>
+
+<p>В браузерах события добавляются в очередь в любое время, если событие произошло, а так же если у него есть обработчик. В случае, если обработчика нет – событие потеряно. Так, клик по элементу, имеющему обработчик события по событию <code>click </code>, добавит событие в очередь, а если обработчика нет – то и событие в очередь не попадет.</p>
+
+<p>Вызов <a href="/ru/docs/Web/API/WindowTimers/setTimeout" title="/en-US/docs/window.setTimeout">setTimeout</a> добавит событие в очередь по прошествии времени, указанного во втором аргументе вызова. Если очередь событий на тот момент будет пуста, то событие обработается сразу же, в противном случае событию функции <code>setTimeout</code> придется ожидать завершения обработки остальных событий в очереди. Именно поэтому второй аргумент <code>setTimeout</code> корректно считать не временем, через которое выполнится функция из первого аргумента, а минимальное время, через которое она сможет выполниться.</p>
+
+<h3 id="Нулевые_задержки">Нулевые задержки</h3>
+
+<p>Нулевая задержка не дает гарантии, что обработчик выполнится через ноль миллисекунд. Вызов {{domxref("WindowTimers.setTimeout", "setTimeout")}} с аргументом  0 (ноль) не завершится за указанное время. Выполнение зависит от количества ожидающих задач в очереди. Например, сообщение ''this is just a message'' из примера ниже будет выведено на консоль раньше, чем произойдет выполнение обработчика <em>сb1</em>. Это произойдет, потому что задержка – это минимальное время, которое требуется среде выполнения на обработку запроса.</p>
+
+<pre class="brush: js">(function () {
+
+ console.log('this is the start');
+
+ setTimeout(function cb() {
+ console.log('this is a msg from call back');
+ });
+
+ console.log('this is just a message');
+
+ setTimeout(function cb1() {
+ console.log('this is a msg from call back1');
+ }, 0);
+
+ console.log('this is the end');
+
+})();
+
+// "this is the start"
+// "this is just a message"
+// "this is the end"
+// "this is a msg from call back"
+// "this is a msg from call back1"</pre>
+
+<h3 id="Связь_нескольких_потоков_между_собой">Связь нескольких потоков между собой</h3>
+
+<p>Web Worker или кросс-доменный фрейм имеют свой собственный стек, кучу и очередь событий. Два отдельных событийных потока могут связываться друг с другом, только через отправку сообщений с помощью метода <code><a href="/en-US/docs/DOM/window.postMessage" title="/en-US/docs/DOM/window.postMessage">postMessage</a>. </code>Этот метод добавляет <code style="font-style: normal;">сообщение</code>  в очередь другого, если он конечно принимает их.</p>
+
+<h2 id="Никогда_не_блокируется">Никогда не блокируется</h2>
+
+<p>Очень интересное свойство цикла событий в JavaScript, что в отличие от множества других языков, поток выполнения никогда не блокируется. Обработка I/O обычно осуществляется с помощью событий и функций обратного вызова, поэтому даже когда приложение ожидает запрос от <a href="/ru/docs/IndexedDB" title="/en-US/docs/IndexedDB">IndexedDB</a> или ответ от <a href="/ru/docs/Web/API/XMLHttpRequest" title="/en-US/docs/DOM/XMLHttpRequest">XHR</a>, оно может обрабатывать другие процессы, например пользовательский ввод.</p>
+
+<p>Существуют хорошо известные исключения как <code style="font-style: normal;">alert</code> или синхронный XHR, но считается хорошей практикой избегать их использования.</p>