Verification: a143cc29221c9be0

Php artisan queue listen не срабатывает

Php artisan queue listen не срабатывает

Page Lifecycle API

Жизненный цикл приложения - это ключевой способ управления ресурсами современных операционных систем. В Android, iOS и последних версиях Windows приложения могут быть запущены и остановлены в любой момент ОС. Это позволяет этим платформам оптимизировать и перераспределять ресурсы там, где они наиболее выгодны пользователю.

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

Хотя на веб-платформе уже давно есть события, связанные с состояниями жизненного цикла, такие как load, unloadи visibilitychange - эти события позволяют разработчикам реагировать только на инициированные пользователем изменения состояния жизненного цикла. Чтобы Интернет мог надежно работать на маломощных устройствах (и в целом уделять больше внимания ресурсам на всех платформах), браузерам необходим способ упреждающего восстановления и перераспределения системных ресурсов.

Фактически, браузеры сегодня уже принимают активные меры по экономии ресурсов для страниц на фоновых вкладках, и многие браузеры (особенно Chrome) хотели бы делать гораздо больше - чтобы уменьшить общий объем ресурсов.

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

Page Lifecycle API пытается решить эту проблему:

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

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

В оставшейся части этого поста будут представлены новые функции жизненного цикла страницы, доступные в Chrome 68, и исследовано, как они связаны со всеми существующими состояниями и событиями веб-платформы. В нем также будут даны рекомендации и передовые методы работы, которую разработчики должны (и не должны) выполнять в каждом штате.

Обзор состояний и событий Lifecycle страницы

Все состояния жизненного цикла страницы являются дискретными и взаимоисключающими, то есть страница может одновременно находиться только в одном состоянии. И большинство изменений в состоянии жизненного цикла страницы обычно можно наблюдать через события DOM (см. Рекомендации разработчика для каждого состояния для исключений).

Возможно, самый простой способ объяснить состояния жизненного цикла страницы, а также события, которые сигнализируют о переходах между ними, - это использовать схему:

Event Loop как устроен цикл событий в браузере,  оптимизация рендеринга ,Page Lifecycle API

состояния

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

State Описание
Active

Страница находится в активном состоянии, если она видна и имеет фокус ввода.

Возможные предыдущие состояния:
passive (через focus событие)

Возможные следующие состояния:
passive (через событие) blur

Passive

Страница находится в passive состоянии, если она видна и не имеет фокуса ввода.

Возможные предыдущие состояния:
активно (по blur событию)
hidden (по событию) visibilitychange

Возможные следующие состояния:
active (через focus событие)
hidden (через событие) visibilitychange

Hidden

Страница находится в скрытом состоянии, если она не видна и не была заморожена.

Возможные предыдущие состояния:
passive (через событие) visibilitychange

Возможные следующие состояния:
passive (через событие) visibilitychange
frozen (через freeze событие)
terminated (через pagehide событие)

Frozen

В frozen состоянии браузер приостанавливает выполнение замораживаемых задач на странице в очереди задач до страницы размораживается. Это означает, что такие вещи, как таймеры JavaScript и обратные вызовы выборки, не работают. Уже запущенные задачи могут завершиться (наиболее важно обратный вызов), но они могут быть ограничены в том, что они могут делать и как долго они могут работать. freeze

Браузеры замораживают страницы, чтобы сохранить загрузку ЦП / батареи / данных; они также делают это, чтобы обеспечить более быструю навигацию назад / вперед, избегая необходимости полной перезагрузки страницы.

Возможные предыдущие состояния:
hidden (через freeze событие)

Возможные следующие состояния:
Terminated

Страница находится в завершенном состоянии после того, как она начала выгрузку и очистку из памяти браузером . Об этом говорит сайт https://intellect.icu . В этом состоянии нельзя запускать новые задачи , а выполняемые задачи могут быть прекращены, если они выполняются слишком долго.

Возможные предыдущие состояния:
hidden (через pagehide событие)

Возможные следующие состояния:
НЕТ

Discarded

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

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

Возможные предыдущие состояния:
frozen (события не запущены)

Возможные следующие состояния:
НЕТ

События

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

имя Детали
focus

Элемент DOM получил фокус.

Примечание:focus событие не обязательно сигнал изменения состояния. Он сигнализирует об изменении состояния только в том случае, если страница ранее не имела фокуса ввода.

Возможные предыдущие состояния:passive

Возможные текущие состояния:active

blur

Элемент DOM потерял фокус.

Примечание:blur событие не обязательно сигнал изменения состояния. Он сигнализирует об изменении состояния только в том случае, если страница больше не имеет фокуса ввода (т.е. страница не просто переключила фокус с одного элемента на другой).

Возможные предыдущие состояния:active

Возможные текущие состояния:passive

visibilitychange

Стоимость документа изменилась. Это может произойти, когда пользователь переходит на новую страницу, переключает вкладки, закрывает вкладку, сворачивает или закрывает браузер или переключает приложения в мобильных операционных системах. visibilityState

Возможные предыдущие состояния:
passive

hidden

Возможные текущие состояния:
passive

hidden

freeze *

Страница только что была заморожена. Любая замораживаемая задача в очередях задач страницы не будет запущена.

Возможные предыдущие состояния:
hidden

Возможные текущие состояния:frozen

resume *

Браузер возобновил остановленную страницу.

Возможные предыдущие состояния:frozen

Возможные текущие состояния:
active (если за ним следует событие) pageshow
passive (если за ним следует событие) pageshow

hidden

pageshow

Переход к записи истории сеанса.

Это может быть либо новая загрузка страницы, либо страница, взятая из обратного кэша . Если страница была взята из Back-Forward Cache, persisted свойство события равно true, в противном случае - false.

Возможные предыдущие состояния:
frozen ( resume событие также сработало)

Возможные текущие состояния:
active
passive

hidden

pagehide

Переход к записи в истории сеанса.

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

Возможные предыдущие состояния:hidden

Возможные текущие состояния:
frozen ( event.persistedверно, событие следует) freeze
terminated ( event.persistedложно, следует событие) unload

beforeunload

Окно, документ и его ресурсы будут выгружены. Документ все еще виден, и на этом этапе событие все еще можно отменить.

Предупреждение:beforeunload событие должно использоваться только для оповещения пользователя о несохраненных изменениях. После сохранения этих изменений событие должно быть удалено. Его никогда не следует добавлять на страницу безоговорочно, поскольку в некоторых случаях это может снизить производительность. Подробности см. В разделе устаревших API .

Возможные предыдущие состояния:hidden

Возможные текущие состояния:terminated

unload

Страница выгружается.

Предупреждение. Использование unloadсобытия никогда не рекомендуется, поскольку оно ненадежно и в некоторых случаях может снизить производительность. Дополнительные сведения см. В разделе устаревших API .

Возможные предыдущие состояния:hidden

Возможные текущие состояния:terminated

* Указывает на новое событие, определенное API жизненного цикла страницы

Новые функции, добавленные в Chrome 68

На приведенной выше диаграмме показаны два состояния, которые инициируются системой, а не пользователем: frozen и отклонено . Как упоминалось выше, браузеры сегодня уже иногда замораживают и удаляют скрытые вкладки (по своему усмотрению), но разработчики не имеют возможности узнать, когда это происходит.

В Chrome 68 разработчики теперь могут следить за замораживанием и размораживанием скрытой вкладки, отслеживая события freeze и .resume document

document.addEventListener('freeze', (event) => {
  // The page is now frozen.
});

document.addEventListener('resume', (event) => {
  // The page has been unfrozen.
});

В Chrome 68 documentобъект теперь также включает wasDiscarded свойство. Чтобы определить, была ли страница отброшена во время нахождения на скрытой вкладке, вы можете проверить значение этого свойства во время загрузки страницы (примечание: для повторного использования отброшенные страницы необходимо перезагрузить).

if (document.wasDiscarded) {
  // Page was previously discarded by the browser while in a hidden tab.
}

Для получения консультации о том , что вещи важно сделать в freezeи resume событиях, а также о том , как обрабатывать и готовить для страниц отбрасываются, см рекомендации для разработчиков каждого государства .

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

Наблюдение за состояниями Lifecycle страницы в коде

В активном , passive и hidden состояниях можно запустить код JavaScript, который определяет текущее состояние жизненного цикла страницы из существующих API веб-платформы.

const getState = () => {
  if (document.visibilityState === 'hidden') {
    return 'hidden';
  }
  if (document.hasFocus()) {
    return 'active';
  }
  return 'passive';
};

С другой стороны, frozen и завершенное состояния могут быть обнаружены только в их соответствующем прослушивателе событий ( freezeи pagehide) по мере изменения состояния.

Наблюдение за изменениями состояния

Основываясь на getState()функции, определенной выше, вы можете наблюдать за всеми изменениями состояния жизненного цикла страницы с помощью следующего кода.

// Stores the initial state using the `getState()` function (defined above).
let state = getState();

// Accepts a next state and, if there's been a state change, logs the
// change to the console. It also updates the `state` value defined above.
const logStateChange = (nextState) => {
  const prevState = state;
  if (nextState !== prevState) {
    console.log(`State change: ${prevState} >>> ${nextState}`);
    state = nextState;
  }
};

// These lifecycle events can all use the same listener to observe state
// changes (they call the `getState()` function to determine the next state).
['pageshow', 'focus', 'blur', 'visibilitychange', 'resume'].forEach((type) => {
  window.addEventListener(type, () => logStateChange(getState()), {capture: true});
});

// The next two listeners, on the other hand, can determine the next
// state from the event itself.
window.addEventListener('freeze', () => {
  // In the freeze event, the next state is always frozen.
  logStateChange('frozen');
}, {capture: true});

window.addEventListener('pagehide', (event) => {
  if (event.persisted) {
    // If the event's persisted property is `true` the page is about
    // to enter the Back-Forward Cache, which is also in the frozen state.
    logStateChange('frozen');
  } else {
    // If the event's persisted property is not `true` the page is
    // about to be unloaded.
    logStateChange('terminated');
  }
}, {capture: true});

Приведенный выше код выполняет три функции:

  • Устанавливает начальное состояние с помощью getState()функции.
  • Определяет функцию, которая принимает следующее состояние и, если есть изменение, записывает изменения состояния в консоль.
  • Добавляет прослушиватели событий для всех необходимых событий жизненного цикла, которые, в свою очередь, вызывают logStateChange()и переходят в следующее состояние.

Предупреждение! Этот код дает разные результаты в разных браузерах, поскольку порядок и надежность событий не были последовательно реализованы. Чтобы узнать, как лучше всего справиться с этими несоответствиями, см. Раздел «Управление различиями между браузерами» .

Следует отметить, что в приведенном выше коде все прослушиватели событий добавляются windowи все проходят {capture: true}. На это есть несколько причин:

  • Не все события жизненного цикла страницы имеют одну и ту же цель. pagehide, и pageshowстреляют window; visibilitychange, freezeи resumeзапускаются document, и focusи blurзапускаются для соответствующих элементов DOM.
  • Большинство этих событий не всплывают, а это означает, что невозможно добавить не фиксирующие прослушиватели событий к общему элементу-предку и наблюдать за ними.
  • Фаза захвата выполняется перед целевой фазой или фазой пузырька, поэтому добавление туда слушателей помогает обеспечить их выполнение до того, как другой код сможет их отменить.

Управление различиями между браузерами

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

Более того, события, реализованные сегодня во всех браузерах, не реализованы последовательно. Например:

  • Некоторые браузеры не запускают blurсобытие при переключении вкладок. Это означает (вопреки диаграмме и таблицам выше) страница может перейти из активного состояния в hidden , не пройдя сначала passive.
  • Некоторые браузеры реализуют обратный кэш , а API жизненного цикла страницы классифицирует кэшированные страницы как находящиеся в frozen состоянии. Так как этот API является новым, эти браузеры еще не реализовать freezeи resumeсобытие, хотя это состояние все еще можно наблюдать с помощью pagehideи pageshowсобытий.
  • В более старых версиях Internet Explorer (10 и ниже) visibilitychangeсобытие не реализовано .
  • Порядок рассылки pagehideи visibilitychangeсобытий изменились . Раньше браузеры отправляли сообщения visibilitychange после pagehideтого, как состояние видимости страницы было видимым, когда страница выгружалась. Новые версии Chrome будут отправлены visibilitychange раньше pagehide, независимо от состояния видимости документа во время выгрузки.
  • Safari не надежно сгореть pagehideили visibilitychange события при закрытии вкладки (WebKit ошибки: 151610 и 151234 ), поэтому в Safari вам , возможно , потребуется также слушать beforeunload события для того , чтобы обнаружить изменения в hidden состоянии. Но поскольку beforeunloadсобытие можно отменить, вам нужно подождать, пока событие не закончит распространение, чтобы узнать, изменилось ли состояние на hidden . Важно : использовать beforeunloadсобытие таким образом следует только в Safari, так как использование этого события в других браузерах может снизить производительность. Подробности см. В разделе устаревших API .

Чтобы разработчикам было легче справляться с этими несоответствиями между браузерами и сосредоточиться исключительно на соблюдении рекомендаций и передовых методов состояния жизненного цикла , мы выпустили PageLifecycle.js , библиотеку JavaScript для наблюдения за изменениями состояния API жизненного цикла страницы.

PageLifecycle.js нормализует кроссбраузерные различия в порядке запуска событий, так что изменения состояния всегда происходят точно так, как указано в диаграмме и таблицах в этой статье (и делают это во всех браузерах).

Рекомендации разработчиков для каждого состояния

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

Например, явно не имеет смысла отображать временное уведомление для пользователя, если страница находится в hidden состоянии. Хотя этот пример довольно очевиден, есть и другие не столь очевидные рекомендации, которые стоит перечислить.

State Рекомендации разработчиков
Active

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

Любая работа, не связанная с пользовательским интерфейсом, которая может блокировать основной поток, должна быть переведена на периоды простоя или передана веб- исполнителю .

Passive

В passive состоянии пользователь не взаимодействует со страницей, но все равно видит ее. Это означает, что обновления пользовательского интерфейса и анимация должны быть плавными, но время появления этих обновлений менее критично.

Когда страница меняется с активной на passive, самое время сохранить несохраненное состояние приложения.

Hidden

Когда страница меняется с passive на hidden , возможно, пользователь не будет с ней взаимодействовать снова, пока она не будет перезагружена.

Переход к hidden также часто последнее изменение состояния , что это надежно наблюдаемым разработчики (это особенно актуально на мобильном телефоне, так как пользователи могут закрывать вкладки или само приложение браузера, а также beforeunload, pagehideи unload события не обжигают в тех случаях).

Это означает, что вы должны рассматривать hidden состояние как вероятный конец сеанса пользователя. Другими словами, сохранять любое несохраненное состояние приложения и отправлять все неотправленные аналитические данные.

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

Frozen

В Frozen состоянии замораживаемые задачи в очередях задач приостанавливаются до тех пор, пока страница не разморозится, что может никогда не произойти (например, если страница будет отброшена).

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

В частности, важно, чтобы вы:

  • Закройте все открытые соединения IndexedDB .
  • Закройте открытые соединения BroadcastChannel .
  • Закройте активные соединения WebRTC .
  • Остановите любой опрос сети или закройте все открытые подключения через веб-сокеты .
  • Снимите все удерживаемые веб-блокировки .

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

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

Terminated

Как правило, вам не нужно предпринимать никаких действий, когда страница переходит в Terminated состояние.

Поскольку страницы, выгружаемые в результате действия пользователя, всегда проходят через hidden состояние перед переходом в состояние завершения , в hidden состоянии должна выполняться логика завершения сеанса (например, сохранение состояния приложения и предоставление отчетов для аналитики).

Кроме того (как указано в рекомендациях для hidden состояния ), разработчикам очень важно понимать, что переход в завершенное состояние не может быть надежно обнаружен во многих случаях (особенно на мобильных устройствах), поэтому разработчики, которые зависят от событий завершения (например beforeunload, pagehide, и unload), вероятно, теряют данные.

Discarded

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

В результате вы должны подготовиться к возможности отмены изменения со hidden на Frozen, а затем вы можете реагировать на восстановление отклоненной страницы во время загрузки страницы, проверяя document.wasDiscarded.

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

Устаревшие API жизненного цикла, которых следует избегать

Событие разгрузки

Ключевой момент: никогда не используйте unloadсобытие в современных браузерах.

Многие разработчики рассматривают unloadсобытие как гарантированный обратный вызов и используют его как сигнал конца сеанса для сохранения состояния и отправки аналитических данных, но делать это крайне ненадежно , особенно на мобильных устройствах! unloadСобытие не срабатывает во многих типичных ситуациях разгрузочных, в том числе закрытия вкладки из вкладок переключателя на мобильном телефоне или закрытие приложения браузера из приложения переключателя.

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

Более того, простое присутствие зарегистрированного unload обработчика событий (с помощью любого onunloadили addEventListener()) может помешать браузерам помещать страницы в кэш обратного направления для более быстрой загрузки вперед и назад.

Во всех современных браузерах (включая IE11) рекомендуется всегда использовать pagehide событие для обнаружения возможных выгрузок страницы (также известного как завершенное состояние), а не unloadсобытие. Если вам нужна поддержка Internet Explorer версии 10 и ниже, вы должны определить pagehideсобытие и использовать его только в том unloadслучае, если браузер не поддерживает pagehide:

const terminationEvent = 'onpagehide' in self ? 'pagehide' : 'unload';

addEventListener(terminationEvent, (event) => {
  // Note: if the browser is able to cache the page, `event.persisted`
  // is `true`, and the state is frozen rather than terminated.
}, {capture: true});

Для получения дополнительной информации о обратном кэшировании и о том, почему событие выгрузки вредит им,

Оптимизация рендеринга браузера

Примечания по оптимизации рендеринга в браузере и плавности до 60 кадров в секунду!

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

Для этого браузер выполняет шесть различных задач:

  1. Скачивание и анализ HTML, CSS и JavaScript
  2. Оценка JavaScript
  3. Расчет стилей для элементов
  4. Размещение элементов на странице - Laying
  5. Рисование фактических пикселей элементов - Painting

Иногда вы можете услышать термин «растеризация», используемый в сочетании с рисованием. Это потому, что рисование на самом деле представляет собой две задачи: 1) создание списка вызовов отрисовки и 2) заполнение пикселей. Последнее называется «растеризацией», поэтому всякий раз, когда вы видите записи рисования в DevTools, вы должны думать об этом как о включении растеризации.

Ставить пользователя в центр производительности

  • 100 миллисекунд
    • Отвечайте на действие пользователя в пределах этого временного окна, и он почувствует, что результат будет немедленным. Если немного больше, то связь между действием и реакцией прерывается.
  • 1 секунда
    • В этом окне все кажется частью естественного и непрерывного выполнения задач. Помимо этого, пользователь потеряет фокус на выполняемой задаче. Для большинства пользователей Интернета загрузка страницы или изменение представлений представляет собой задачу.
  • 16 миллисекунд
    • Учитывая, что экран обновляется 60 раз в секунду, это окно представляет время, за которое на экран выводится один кадр (профессор Математик говорит, что 1000 ÷ 60 = ~ 16). Люди исключительно хороши в отслеживании движения, и им не нравится, когда их ожидания движения не выполняются - либо из-за переменной частоты кадров, либо из-за периодических остановок.

Event Loop как устроен цикл событий в браузере,  оптимизация рендеринга ,Page Lifecycle API

60 кадров в секунду = 16 мс / кадр, но на самом деле у вас есть только 10–12 мс на выполнение всей работы из-за накладных расходов браузера.

Жизненные циклы приложений (RAIL)

  • отклик Response
  • Анимации Animations
  • Холостой ход Idle
  • Load Загрузка (XHR, Websockets, импорт HTML и т. Д.)

Event Loop как устроен цикл событий в браузере,  оптимизация рендеринга ,Page Lifecycle API

Актуальный хронологический порядок

  1. Загрузить (~ 1 сек) Начальная загрузка страницы. Загрузите и отобразите здесь свои критически важные ресурсы.
  2. Бездействие (фрагменты ~ 50 мс) Выполняйте всю несущественную работу, чтобы взаимодействия, которые происходят позже, казались мгновенными. например. ленивая загрузка элементов, выполнение предварительных расчетов анимации и т. д.
  3. Ответ (~ 100 мс) При взаимодействии ответ в течение 100 мс.
  4. Анимация (~ 16 мс) На самом деле мы получаем ~ 12 мс, поскольку у браузера есть некоторые накладные расходы.

Event Loop как устроен цикл событий в браузере,  оптимизация рендеринга ,Page Lifecycle API

Что происходит при смене стиля?

Например, во время изменения непрозрачности или анимации преобразования запускается только композит.

  • Страница не получает новый HTML, поэтому не нужно создавать DOM.
  • Страница не получает новый CSS, поэтому создавать CSSOM не нужно.
  • Страница не получает новый HTML или CSS, поэтому трогать дерево рендеринга не нужно.
  • Если изменение непрозрачности или трансформации влияет на элемент на его собственном слое, макет запускать не нужно.
  • Если изменение непрозрачности или трансформации влияет на элемент на его собственном слое, рисовать не нужно.

Чтобы код JavaScript работал быстрее

  • Не зацикливайтесь на микрооптимизации, например. for-loop vs while и т. д., поскольку разные движки JS (V8 и т. д.) обрабатывают его по-разному.
  • JS может запускать каждую часть конвейера рендеринга (изменения стиля, макета, рисования и компоновки), следовательно, запускать его как можно раньше в каждом кадре.

Анимация(Animation)

  • requestAnimationFrame - это инструмент перехода для создания анимации.
    • Планирует запуск JavaScript как можно раньше в каждом кадре.
    • Браузер может оптимизировать параллельные анимации вместе в один цикл перекомпоновки и перерисовки, что приводит к более точной анимации. Например, анимация на основе JS, синхронизированная с переходами CSS или SVG SMIL.
    • Кроме того, если вы запускаете цикл анимации на вкладке, которая не отображается, браузер не будет поддерживать ее работу, что означает меньшее использование ЦП, графического процессора и памяти, что приведет к гораздо более длительному времени автономной работы.
  • Браузер должен отображать кадры со скоростью 60 кадров в секунду, т.е. 16 мс / кадр.
    • Из-за накладных расходов браузера мы получаем около 10 мс, поэтому у JS есть время около 3 мс.
  • JavaScript -> Стиль -> Макет -> Рисование -> Составной
  • Не используйте setTimout или setInterval для анимации, так как JS-движок не обращает внимания на конвейер рендеринга при выполнении этого.
  • Для IE9 - используйте requestAnimationFrame с Polyfill.

Веб-воркеры (Webworkers)

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

Event Loop как устроен цикл событий в браузере,  оптимизация рендеринга ,Page Lifecycle API

Стили и макет (пересчет стилей) Styles and Layout (Recalc Styles)

  • Стоимость пересчета стилей линейно зависит от количества элементов на странице.
  • БЭМ : модификатор элемента блока: используйте этот стиль для селекторов CSS.
  • Сопоставление классов часто является самым быстрым селектором в современных браузерах.
  • Сокращение времени на «Пересчет стилей».
    • Уменьшить затронутые элементы (меньше изменений в дереве рендеринга)
    • Снижение сложности селектора (меньше тегов и имен классов для выбора элементов)
  • «Принудительный синхронный макет» возникает, когда вы просите браузер сначала запустить «макет» внутри раздела JavaScript, а затем выполнить расчет «стиля», а затем снова запустить макет. Постарайтесь этого избежать. Инструменты разработчика Chrome (таблица пламени) помогают определить это.
  • Прочтите свойства макета и внесите пакетные изменения в стиль, чтобы максимально избежать запуска макета.
  • Разбивка макета происходит, когда вы выполняете «принудительную синхронную компоновку» много раз подряд.

Repaints and Reflows

Рисование - это процесс, с помощью которого браузер берет свою абстрактную коллекцию элементов со всеми их свойствами и фактически вычисляет пиксели для рисования. Это включает в себя вычисление стилей, таких как тени и градиенты блоков, а также изменение размеров изображений. Перерисовка происходит, когда в оболочку элементов вносятся изменения, которые изменяют видимость, но не влияют на ее макет. Примеры этого включают контур, видимость или цвет фона. Согласно Opera, перерисовка обходится дорого, потому что браузер должен проверять видимость всех других узлов в дереве DOM.

Перекомпоновка еще более критична для производительности, потому что она включает изменения, влияющие на макет части страницы (или всей страницы). Перекомпоновка элемента вызывает последующую перекомпоновку всех дочерних элементов и элементов-предков, а также любых элементов, следующих за ним в DOM. Согласно Opera, большинство перекомпоновок по существу вызывают перерисовку страницы.

Итак, если они настолько ужасны для производительности, что вызывает перекомпоновку?

К сожалению, много чего. Среди них некоторые, которые особенно важны при написании CSS:

  • Изменение размера окна.
  • Смена шрифта.
  • Добавление или удаление таблицы стилей.
  • Изменения содержимого, например, когда пользователь вводит текст в поле ввода.
  • Активация псевдоклассов CSS, таких как: hover (в IE активация псевдокласса родственного брата)
  • Манипулирование атрибутом класса.
  • Скрипт, управляющий DOM.
  • Расчет offsetWidth и offsetHeight.
  • Установка свойства атрибута стиля

Для полного списка проверьте суть Пола Айриша