Movatterモバイル変換


[0]ホーム

URL:


MDN Web Docs

Эта страница была переведена с английского языка силами сообщества. Вы тоже можете внести свой вклад, присоединившись к русскоязычному сообществу MDN Web Docs.

Цикл событий

Поток выполнения в JavaScript работает за счёт цикла событий (event loop), который отвечает за выполнение кода, сбора и обработки событий и выполнения под-задач из очереди (queued sub-tasks). Эта модель весьма отличается от других языков программирования, таких как C и Java.

Концепция жизненного цикла

В следующей секции объясняется теоретическая модель. Современные JavaScript движки внедряют/имплементируют и существенно оптимизируют этот процесс.

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

Stack, heap, queue

Для лучшеговизуального представления работыEvent loop, Вы можете ознакомиться с данным видео:https://www.youtube.com/watch?v=8aGhZQkoFbQ&t=389s

Стек

Вызов любой функции создаёт контекст выполнения (Execution Context). При вызове вложенной функции создаётся новый контекст, а старый сохраняется в специальной структуре данных - стеке вызовов (Call Stack).

js
function f(b) {  var a = 12;  return a + b + 35;}function g(x) {  var m = 4;  return f(m * x);}g(21);

Когда вызывается функцияg, создаётся первый контекст выполнения, содержащий аргументы функцииg и локальные переменные. Когдаg вызываетf, создаётся второй контекст с аргументамиf и её локальными переменными. И этот контекст выполненияf помещается в стек вызовов выше первого. Когдаf возвращает результат, верхний элемент из стека удаляется. Когдаg возвращает результат, её контекст также удалится, и стек становится пустым.

Куча

Объекты размещаются вкуче. Куча — это просто имя для обозначения большой неструктурированной области памяти.

Очередь

Среда выполнения JavaScript содержит очередь задач. Эта очередь — список задач, подлежащих обработке. Каждая задача ассоциируется с некоторой функцией, которая будет вызвана, чтобы обработать эту задачу.

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

Обработка задачи заканчивается, когда стек снова становится пустым. Следующая задача извлекается из очереди и начинается её обработка.

Цикл событий

Модель событийного цикла (event loop) называется так потому, что отслеживает новые события в цикле:

js
while (queue.waitForMessage()) {  queue.processNextMessage();}

queue.waitForMessage ожидает поступления задач, если очередь пуста.

Запуск до завершения

Каждая задача выполняется полностью, прежде чем начнёт обрабатываться следующая. Благодаря этому мы точно знаем: когда выполняется текущая функция – она не может быть приостановлена и будет целиком завершена до начала выполнения другого кода (который может изменить данные, с которыми работает текущая функция). Это отличает JavaScript от такого языка программирования как C. Поскольку в С функция, запущенная в отдельном потоке, в любой момент может быть остановлена, чтобы выполнить какой-то другой код в другом потоке.

У данного подхода есть и минусы. Если задача занимает слишком много времени, то веб-приложение не может обрабатывать действия пользователя в это время (например, скролл или клик). Браузер старается смягчить проблему и выводит сообщение"скрипт выполняется слишком долго" ("a script is taking too long to run") и предлагает остановить его. Хорошей практикой является создание задач, которые исполняются быстро, и если возможно, разбиение одной задачи на несколько мелких.

Добавление событий в очередь

В браузерах события добавляются в очередь в любое время, если событие произошло, а так же если у него есть обработчик. В случае, если обработчика нет – событие потеряно. Так, клик по элементу, имеющему обработчик события по событиюclick, добавит событие в очередь, а если обработчика нет – то и событие в очередь не попадёт.

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

Нулевые задержки

Нулевая задержка не даёт гарантии, что обработчик выполнится через ноль миллисекунд. ВызовsetTimeout с аргументом 0 (ноль) не завершится за указанное время. Выполнение зависит от количества ожидающих задач в очереди. Например, сообщение ''this is just a message'' из примера ниже будет выведено на консоль раньше, чем произойдёт выполнение обработчикаcb1. Это произойдёт, потому что задержка – это минимальное время, которое требуется среде выполнения на обработку запроса.

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"

Связь нескольких потоков между собой

Web Worker или кросс-доменный фрейм имеют свой собственный стек, кучу и очередь событий. Два отдельных событийных потока могут связываться друг с другом, только через отправку сообщений с помощью методаpostMessage. Этот метод добавляет сообщение в очередь другого, если он конечно принимает их.

Никогда не блокируется

Очень интересное свойство цикла событий в JavaScript, что в отличие от множества других языков, поток выполнения никогда не блокируется. Обработка I/O обычно осуществляется с помощью событий и колбэк-функций, поэтому даже когда приложение ожидает запрос отIndexedDB или ответ отXHR, оно может обрабатывать другие процессы, например пользовательский ввод.

Существуют хорошо известные исключения какalert или синхронный XHR, но считается хорошей практикой избегать их использования.

Help improve MDN

Learn how to contribute.

This page was last modified on byMDN contributors.


[8]ページ先頭

©2009-2025 Movatter.jp