Гарантируется ли рендеринг DOM для блокировки во время выполнения одной (синхронной) функции?
Блокировка DOM - это то, что многие люди, не знакомые со строго однопоточной моделью синхронного выполнения JavaScript, узнают о сложном пути, и обычно нам просто нужно как-то обойти это (используя таймауты, веб-работников и т. Д.). Все хорошо.
Тем не менее, я хотел бы знать, действительно ли вы можете положиться на блокирование реального визуализируемого пользователем рендеринга. Я на 90% уверен, что это так и есть в большинстве браузеров, но я надеюсь, что это не просто случайный случай. Я не могу найти какие-либо окончательные утверждения из спецификаций DOM или даже документации поставщика, как MDM.
Что меня немного беспокоит, так это то, что хотя изменения DOM действительно не видны при просмотре страницы, внутренняя геометрия DOM (включая CSS-преобразования и фильтры) действительно обновляется во время синхронного выполнения. Например:
console.log(element.getBoundingRect().width);
element.classList.add("scale-and-rotate");
console.log(element.getBoundingRect().width);
element.classList.remove("scale-and-rotate");
... действительно сообщит о двух разных значениях ширины, хотя страница не будет мигать. Синхронное ожидание после добавления класса (с использованием цикла while) также не делает видимыми временные изменения. Выполнение трассировки временной шкалы в Chrome показывает, что внутреннее рисование и перерисовка происходят точно так же, что имеет смысл...
Я обеспокоен тем, что в отсутствие конкретной причины некоторые браузеры, например, те, которые работают с маломощными мобильными процессорами, могут на самом деле отразить эти внутренние вычисления в видимой для пользователя компоновке во время выполнения этой функции, что приведет к уродливому "мигать" во время таких временных операций. Итак, более конкретно, я спрашиваю: есть ли у них конкретная причина не делать этого?
(Если вам интересно, почему я вообще об этом беспокоюсь, мне иногда нужно измерять рассчитанные размеры, используя getBoundingRect
для элементов в определенном состоянии планировать интервалы, анимацию или другие подобные вещи, фактически не переводя их в это состояние или не анимируя их первыми...)
2 ответа
В Javascript нет ничего, связанного с параллелизмом, кроме де-факто. JS просто не определяет модель параллелизма. Все это счастливая случайность или годы консенсуса.
Тем не менее, если ваша функция не вызывает какие-либо странные вещи, такие как XMLHttpRequest или "alert", или что-то в этом роде, вы можете рассматривать ее как однопотоковую без прерываний.
Согласно различным источникам, получение позиции или размера элемента DOM вызовет перерисовку вывода при необходимости, чтобы возвращаемые значения были правильными. На самом деле, читая offsetHeight
Элемент стал способ заставить перекрасить, как сообщают Александр Скутин и Даниэль Нортон.
Пол Айриш приводит список нескольких действий, которые вызывают перекрашивание или перекомпоновку. Среди них есть следующие методы и свойства метрик элементов:
- elem.offsetLeft, elem.offsetTop, elem.offsetWidth, elem.offsetHeight,
- elem.offsetParent elem.clientLeft, elem.clientTop, elem.clientWidth,
- elem.clientHeight elem.getClientRects (), elem.getBoundingClientRect ()
Стоян Стефанов описывает стратегии, используемые браузерами для оптимизации перерисовок (например, очереди изменений DOM и выполнения их в пакетном режиме), и добавляет следующее замечание:
Но иногда скрипт может помешать браузеру оптимизировать перекомпоновки и заставить его очистить очередь и выполнить все пакетные изменения. Это происходит, когда вы запрашиваете информацию о стиле, такую как
- offsetTop, offsetLeft, offsetWidth, offsetHeight
- scrollTop / лево / ширина / высота
- clientTop/ лево / ширина / высота
- getComputedStyle() или currentStyle в IE
Все это, по сути, запрашивает информацию о стиле узла, и каждый раз, когда вы это делаете, браузер должен предоставить вам самую актуальную информацию. Для этого ему необходимо применить все запланированные изменения, очистить очередь, откусить пулю и выполнить перекомпоновку.