Рубрики
Без рубрики

Цикл событий JavaScript и пояснил стек вызова

Первоначально опубликовано в моем блоге: цикл событий JavaScript и пояснил стек вызова Моя цель с этим … Помечено JavaScript, WebDev.

Первоначально опубликовано в моем блоге: Цикл событий JavaScript и пояснил стек вызова

Моя цель с этой статьей – научить вас, как работает JavaScript в браузере. Несмотря на то, что я работаю с JavaScript за всю мою карьеру, я не получил, как эти вещи работают до недавнего времени.

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

Я хочу сделать эту статью так легко понять, насколько это возможно. Если у вас есть какие-либо открытые вопросы, пожалуйста, пришлите мне Email или оставить комментарий. Я постараюсь помочь вам и улучшить статью с вашими отзывами.

Как работает JavaScript в браузере

Прежде чем я погрузился в объяснение каждой темы, я хочу, чтобы вы посмотрели на это Обзор высокого уровня Что я создал, что является абстракцией того, как JavaScript взаимодействует с браузером.

Не волнуйтесь, если вы не знаете, что означают все условия. Я охвачу каждую из них в этом разделе.

Обратите внимание, как большинство вещей в графике не являются частью самого языка JavaScript. Web API, очередь обратного вызова и цикл событий – это все функции, которые предоставляют браузер.

Представление Nodejs будет выглядеть похоже, но в этой статье я сосредоточусь на том, как работает JavaScript в браузере.

Стек вызовов

Вы, вероятно, уже слышали, что JavaScript является однопоточным. Но что это значит?

JavaScript может сделать одну вещь за раз Потому что у него есть только один стек вызовов.

Стек вызовов – это механизм, который помогает переводчику JavaScript для Следите за функциями, которые скрипт звонит Отказ

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

Функция либо выходит через оператор возврата, либо путем достижения конца объема.

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

Порядок, в котором стек Процессы Каждый вызов функции выполняет принцип Lifo (в последний раз, во-первых).

Шаги предыдущего примера следующие:

  1. Файловые нагрузки и Главная Функция называется, которая обозначает выполнение всего файла. Эта функция – добавлено в стек вызова.
  2. Главная звонки Расчет () , Вот почему это добавлено к верхней части стека вызовов.
  3. Расчет () звонки AddTree () , который снова добавлено в стек вызова.
  4. AddTree звонки Addtwo , что это добавлено в стек вызова.

  1. Addone не вызывает никаких других функций. Когда он выходит, это Удален из стека вызовов.
  2. С результатом Addone , Addtwo выходит также и это Удален из стека вызовов.
  3. AddTree это Удален также.
  4. Расчет звонки Addtwo , который добавляет это в стек вызова.
  5. Addtwo звонки Addone и добавляет это в стек вызова.
  6. Addone Выход и это удаленный из стека вызовов.
  7. Addtwo Выход и это удаленный из стека вызовов.
  8. Расчет может выйти сейчас с результатом AddTree и addtwo. и это удаленный из стека вызовов.
  9. В файле нет дальнейших заявлений или звонков функций, поэтому Главная выходит также и это Удален из стека вызовов.

Я назвал контекст, который выполняет наш код Главная , но это не то, как официальное название функции. В сообщениях об ошибках, которые вы можете найти в консоли браузера, имя этой функции – анонимный Отказ

Uncaught rangeError: превышен максимальный размер стека вызова

Вы, вероятно, знаете стек вызова от отладки вашего кода. Uncaught russeRor: Максимальный размер стека вызовов превышен является одним из ошибок, которые вы могли бы столкнуться. Ниже мы можем увидеть снимок CallStack, когда произошла ошибка.

Следуйте за следом стека этого сообщения об ошибке. Он представляет собой функции вызывают, которые привели к этой ошибке. В этом случае ошибка была в функции B, которая была вызвана A (которая была вызвана B и так далее).

Если вы видите это конкретное сообщение об ошибке на экране, Одна из ваших функций позвонила слишком много функций Отказ Максимальный размер вызовов размером от От 10 до 50 тысяч звонков Так что, если вы превышаете это, это, скорее всего, у вас есть бесконечный цикл в вашем коде.

Браузер предотвращает вашу код от замораживания всей страницы, ограничивая стек вызова.

Я повторно создал ошибку со следующим кодом. Способ предотвращения этого – либо не использовать рекурсивные функции в первую очередь, либо путем предоставления базового случая, что делает ваш выход в какой-то момент.

function a() {
    b();
}

function b() {
    a();
}

a();

Таким образом, стек вызовов отслеживает вызовы функций в вашем коде. Отсюда следует Lifo принцип (Последнее, во-первых, во-первых), что означает, что он всегда обрабатывает вызов, который находится сверху стека.

JavaScript имеет только один стек вызовов, поэтому он может сделать только одну вещь за раз.

Куча

Куча JavaScript – где объекты хранятся Когда мы определяем функции или переменные.

Поскольку он не влияет на стек вызовов и петли события, было бы вне сферы этой статьи, чтобы объяснить, как работает распределение памяти JavaScript.

Я планирую написать сообщение в блоге по этой теме. Если вы еще этого не сделаете, убедитесь, что Подписаться на мою рассылку получить уведомление, когда это выходит.

Web API

Выше я сказал, что JavaScript может сделать только одну вещь за раз.

Хотя это верно для самого языка JavaScript, вы все еще можете делать вещи одновременно в браузере Отказ Поскольку название уже предлагает, это возможно через API, которые предоставляют браузеры.

Давайте посмотрим, как мы производим запрос API. Если мы выполнили код в интерпретатере JavaScript, мы не сможем сделать что-то еще, пока мы не получим ответ с сервера.

Это в значительной степени делает веб-приложения непригодными для использования.

В качестве решения для этого веб-браузеры дают нам API, которые мы можем позвонить в наш код JavaScript. Исполнение, однако, обрабатывается по самой платформе Вот почему Это не заблокирует стек вызова Отказ

Еще одно преимущество Web API в том, что они написаны в Низкоуровневый код (Как и в), что позволяет им делать то, что просто невозможно в простом JavaScript.

Они позволяют вам делать запросы AJAX или манипулировать DOM, но и ряда других вещей, таких как гео-отслеживание, доступ к местному хранению, работникам обслуживания и многое другое.

Если вы заинтересованы в каких новых API, мы можем ожидать поверхности в будущем, проверить Моя статья о проекте Фугу , бессмысленные усилия, привлекли к жизни Google, что наметиется приносить более родные функции на веб-платформу.

Обратный вызов очереди

С функциями Web API теперь мы можем делать вещи одновременно вне переводчика JavaScript. Но Что произойдет, если мы хотим, чтобы наш код JavaScript реагируйте на результат веб-API, например, запрос AJAX?

Вот где обратные вызовы вступают в игру. Через них веб-API позволяют нам Запустите код после выполнения вызова API закончил.

Что такое обратный вызов?

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

Вы можете создавать функции обратного вызова, написав функции, которые принимают функцию в качестве аргумента. Такие функции, также известны как Функции высшего порядка Отказ Обратите внимание, что обратные вызовы не по умолчанию асинхронно.

Давайте посмотрим на пример:

const a = () => console.log('a');
const b = () => setTimeout(() => console.log('b'), 100);
const c = () => console.log('c');

a();
b();
c();

Setimeate Добавляет тайм-аут X MS до выполнения обратного вызова.

Вы, вероятно, уже можете думать о том, как будет выглядеть вывод.

Setimeate выполняется одновременно, в то время как интерпретатор JS продолжает выполнять следующие утверждения.

Когда прошел время ожидания и Стек вызовов снова пуст, функция обратного вызова, которая была передана на Setimeate будет выполнено.

Окончательный вывод будет выглядеть так:

a
c
b
Но как насчет очереди обратного вызова?

Теперь после Setimeate Заканчивает его выполнение, он не сразу называет функцию обратного вызова. Но почему?

Помните, что JavaScript может сделать только одну вещь за раз?

Обратный вызов, который мы передали как аргумент для Setimeate написано в JavaScript Отказ Таким образом, интерпретатор JavaScript должен запустить код, что означает, что ему необходимо использовать стек вызова, который снова означает, что мы должны Подождите, пока стек вызовов не будет пустым Для того, чтобы выполнить обратный вызов.

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

Призыв Setimeate триггеры выполнения Веб-API, который добавляет обратный вызов к очереди обратного вызова . Затем контур событий требует обратного вызова из очереди и добавляет его в стек, как только он пуст.

Несколько вещей происходит здесь одновременно. Следуйте по пути, которое выполнение Setimeate берет, а в другом запуске сосредоточиться на том, что делает стек вызова.

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

Контур событий

Контур событий JavaScript принимает первый вызов в очереди обратного вызова и добавляет его в стек вызова, как только он пуст.

Код JavaScript работает в процессе запуска, что означает, что если стек вызова в настоящее время выполняется какой-то код, цикл события заблокирован и Не добавим никаких вызовов из очереди, пока стек снова не будет пуст Отказ

Вот почему важно не заблокировать стек вызовов, запустив вычисление-интенсивные задачи.

Если вы выполняете слишком много кода или засоряете очередь обратного вызова, ваш сайт станет не отвечает, потому что он не может выполнить любой новый код JavaScript.

Обработчики событий, как onscroll Добавьте больше заданий в очередь обратного вызова при срабатывании. Вот почему вы должны отложить эти обратные вызовы, что означает, что они будут выполнены только каждый х мс.

Увидеть это для себя

Добавьте следующий код в консоль браузера. Когда вы прокрутите, вы можете наблюдать, как часто принты обратного вызова Свиток Отказ

window.onscroll = () => console.log('scroll');

Setimeate (FN, 0) или Setimmediate ()

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

Размещение асинхронного кода в обратный вызов и настройка Setimeate до 0 мс позволит браузеру делать такие вещи, как обновление DOM, прежде чем продолжить с выполнением обратного вызова.

Очередная очередь и асинхронный код

В обзоре, что я показал в начале, я оставил одну дополнительную функцию, которая важно знать.

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

Обещания: Быстрое повторение

Emmascript 2015 (или ES6) впервые ввел обещания, даже если он был доступен до того, как в Вавиле.

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

setTimeout(() => {
  console.log('Print this and wait');
  setTimeout(() => {
    console.log('Do something else and wait');
    setTimeout(() => {
      // ...
    }, 100);
  }, 100);
}, 100)

С помощью воображения вы можете посмотреть, как обратные вызовы Chaining могут в конечном итоге Пирамида гибели -Ори прямо уродливый код.

С обещаниями этот код может стать гораздо более читаемым:

// A promise wrapper for setTimeout
const timeout = (time) => new Promise(resolve => setTimeout(resolve, time));
timeout(1000)
  .then(() => {
    console.log('Hi after 1 second');
    return timeout(1000);
  })
  .then(() => {
    console.log('Hi after 2 seconds');
  });

Этот код выглядит еще более читабельно с async / ждать синтаксис:

const logDelayedMessages = async () => {
  await timeout(1000);
  console.log('Hi after 1 second');
  await timeout(1000);
  console.log('Hi after 2 seconds');
};

logDelayedMessages();

Это был быстрый реконструкцию о том, как работают обещания, но в этой статье я не буду погружаться глубже в эту тему. Проверьте MDN веб-документы Если вы хотите узнать больше о них.

Где обещания вписываются?

Почему я говорю о обещаниях здесь?

Имея большую картину, обещания ведут себя немного иначе, чем обратные вызовы, потому что У них есть своя очередь Отказ

Очередь работы , также известный как очередь обещания, имеет приоритет над очередью обратного вызова Похоже, что очередь быстрой дорожки в парке развлечений.

Спектакль событий сначала примет звонки из очереди обещания перед обработкой очереди обратного вызова.

Давайте посмотрим на пример:

console.log('a');
setTimeout(() => console.log('b'), 0);
new Promise((resolve, reject) => {
  resolve();
})
.then(() => {
  console.log('c');
});
console.log('d');

Принимая во внимание ваши знания о том, как работают очереди обратного вызова, вы можете подумать, что вывод будет A D B C Отказ

Но потому что Обеспечение очереди имеет приоритет над очередью обратного вызова , C будет напечатан до B Несмотря на то, что оба асинхронные:

a
d
c
b

Вывод

Я надеюсь, что у вас есть лучшее понимание того, что происходит за кулисами вашего кода JavaScript. Как я уже упоминал в начале, если у вас есть какие-либо вопросы или обратная связь, пожалуйста, оставьте комментарий.

Я также узнал этот материал в Интернете, вот ресурсы, которые помогли мне понять эту тему:

Лучший разговор/видео там на этой теме. Я настоятельно рекомендую вам проверить это.

Инструменты, позволяющие визуализировать, как выполняется ваш код.

Больше художеств, которые вас могут быть заинтересованы в:

  • Мои 9 любимых тем “прагматичный программист”

Чтение – отличный способ улучшить ваши навыки программирования. В этой статье я делюсь своими ключами в моей любимой книге программирования.

  • Как сделать ваше приложение React Progressive Web App (PWA)

Полная прогулка по тому, как вы можете сделать ваше приложение React App A Прогрессивный Веб-приложение (это проще, чем звучит).

Оригинал: “https://dev.to/fgerschau/javascript-event-loop-and-call-stack-explained-1mfk”