Я не полностью понимаю JavaScript Threading - PullRequest
5 голосов
/ 05 марта 2011

Прежде чем погрузиться в вопрос. Позвольте мне заявить, что в цикле событий я имею в виду http://en.wikipedia.org/wiki/Event_loop. Это то, что реализуют браузеры. Для получения дополнительной информации читайте это: http://javascript.info/tutorial/further-javascript-features/events-and-timing-depth.

Этот вопрос сложный и длинный, поэтому, пожалуйста, постарайтесь с ним смириться! И я ценю все ответы!


Итак. Теперь, насколько я понимаю, в JavaScript есть один основной поток (то есть в большинстве браузерных сред). Итак, код вроде:

for (var color = 0x000; color < 0xfff; color++) {
    $('div').css('background-color', color.toString(16));
}

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

Если вы хотите увидеть анимацию, вы можете сделать:

for (var color = 0x000; color < 0xfff; color++) {
    setTimeout(function() {
        $('div').css('background-color', color.toString(16));
    }, 0);
}

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

Кажется, что в этом случае в браузере есть события 0xfff (4095), помещенные в стек, где каждое из них обрабатывается с процессом рендеринга между ними. Итак, мой первый вопрос (# 1): когда именно происходит рендеринг? Всегда ли это происходит между обработкой двух событий в стеке циклов событий?


Второй вопрос касается кода в ссылке на веб-сайте javascript.info, которую я вам дал.

...
  function func() { 
    timer = setTimeout(func, 0)
    div.style.backgroundColor = '#'+i.toString(16)
    if (i++ == 0xFFFFFF) stop()
  }

timer = setTimeout(func, 0)
....

Мой вопрос здесь заключается в том, будет ли браузер отправлять новое событие «рендеринга» в стек цикла событий каждый раз, когда оно достигает строки div.style. ... = ...? Но разве это не сначала выдвигает событие из-за вызова setTimeout? Итак, браузер оказывается в стеке как:

setTimeout event
render event

Поскольку вызов setTimeout обрабатывался до изменения стиля div? Если так выглядит стек, то я предполагаю, что в следующий раз, когда браузер войдет в цикл обработки событий, он обработает обратный вызов setTimeout и в итоге получит:

rendering event
setTimeout event
rendering event

и продолжить с событием рендеринга, которое произвел предыдущий вызов setTimeout?

Ответы [ 2 ]

6 голосов
/ 05 марта 2011

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

Попробуйте: http://taligarsiel.com/Projects/howbrowserswork1.htm#Render_tree_construction (документ датирован октябрем 2009 года, т. Е. Достаточно актуален)

Q2:Рендеринг не обязательно совпадает с исполнением JS - это два разных движка.Этот движок JS не отвечает за рендеринг, он просто взаимодействует с движком рендеринга.Мне кажется, главное сообщение для вашего второго вопроса - это независимость JS от движка рендеринга .Помните, что браузер (или веб-страница) не нуждается в Javascript, их основное назначение - визуализация HTML на основе правил стиля CSS.Javascript - это всего лишь один из способов манипулирования HTML (в действительности, деревом DOM) и правилами стилей.

Обратите внимание, что вы можете форсировать рендеринг, читая определение стиля - на данный момент у движка рендеринга нет выбора, кроме как обработать любойвыдающиеся изменения стиля, особенно если это связано с изменениями позиции.Вот почему следует удалить объекты из дерева рендеринга (например, установив display: none - visibility: hidden не достаточно, так как размер элемента все еще учитывается для макета), прежде чем делать много изменений стиля или добавлять много элементов, например, когдамножество строк добавляются одна за другой (цикл for) к таблице.

Совсем не вопрос, но я только что упомянул разницу между display: none и visibility: hidden, этоТакже следует учитывать при добавлении скрытой позиции: абсолютные элементы, такие как диалоги.Хотя нет видимой разницы, является ли абсолютно позиционированный элемент скрытым от вас, используя тот или иной метод, внутренне существует большая разница: при скрытии с использованием видимости: скрытый элемент является частью дерева рендеринга, с отображением: нетне.Поэтому, если у вас есть такой элемент, который нужно много переключать, следует использовать visibility: hidden, потому что, когда стиль «display» переключается между «none» и, например, «block», браузер должен сначала отобразить его.

1 голос
/ 05 марта 2011

В статье, которую вы упоминаете, рассматривается только Javascript. Многое происходит в браузере; Перекраска и перекрашивание могут / могут быть вызваны гораздо большим количеством вещей; взгляните на следующие ссылки для получения дополнительной информации об этом.

Я бы не использовал setTimeout для этой цели.

Изменить: Согласно комментариям, рекомендуемый способ заключается в использовании requestAnimationFrame. На момент написания статьи это доступно только в нестабильных выпусках большинства браузеров. Однако имеется несколько библиотек , обеспечивающих кросс-браузерный доступ к ним, и при необходимости прибегают к использованию setTimeout.

Взгляните на эту демонстрацию для примера работы в старых браузерах, а также в новых: http://paulirish.com/2011/requestanimationframe-for-smart-animating/

...