Когда я хочу выполнить исполнение своего javascript и разрешить браузеру применять стили и т. Д., Прежде чем продолжить, я, как правило, использую общую технику setTimeout
с задержкой 0
, чтобы иметь обратный вызов, поставленный в очередь в конце цикла событий. Однако я столкнулся с ситуацией, когда это, похоже, не работает надежно.setTimeout (fn, 0) триггер перед стилями были применены
В приведенном ниже фрагменте есть класс active
, применяющий переход к элементу chaser
.
Когда я парить над целевой DIV, я хочу, чтобы удалить active
класс от chaser
элемента, переместите chaser
на новое место, а затем повторно использовать active
класс. Эффект должен заключаться в том, что o
должен немедленно исчезнуть, а затем исчезнуть в новом месте. Вместо этого используются как opacity
, так и top
, поэтому o
слайд с позиции на позицию, большую часть времени.
Если я увеличиваю задержку внутреннего таймаута до 10
, он начинает вести себя так, как я и предполагал. Если я установил его на 5
, то он иногда делает, а иногда нет.
Я бы ожидал, что любой setTimeout
поставит в очередь мой обратный вызов до тех пор, пока не будут применены обновления стиля, но здесь есть четкое условие гонки. Я что-то упускаю? Есть ли способ гарантировать порядок обновления?
Я нахожусь на Chrome 56 на macOS и Windows, еще не проверял другие браузеры.
(Я знаю, что могу достичь этого другими способами, такими как применение перехода только к свойству opacity
- пожалуйста, рассмотрите этот надуманный пример, чтобы продемонстрировать конкретный вопрос о заказе обновлений стиля).
var targets = document.querySelectorAll('.target');
var chaser = document.querySelector('#chaser');
for (var i = 0; i < targets.length; i++) {
targets[i].addEventListener('mouseenter', function(event) {
chaser.className = '';
setTimeout(function() {
// at this point, I'm expecting no transition
// to be active on the element
chaser.style.top = event.target.offsetTop + "px";
setTimeout(function() {
// at this point, I'm expecting the element to
// have finished moving to its new position
chaser.className = 'active';
}, 0);
}, 0);
});
}
#chaser {
position: absolute;
opacity: 0;
}
#chaser.active {
transition: all 1s;
opacity: 1;
}
.target {
height: 30px;
width: 30px;
margin: 10px;
background: #ddd;
}
<div id="chaser">o</div>
<div class="target">x</div>
<div class="target">x</div>
<div class="target">x</div>
<div class="target">x</div>
<div class="target">x</div>
что, если вместо SetTimeout (Fn, 0) вы используете requestAnimationFrame. Если вы выполните двойной запросAnimationFrame, я бы подумал, что браузер должен быть обновлен. – David
@ Давид может работать, не уверен, дает ли он какие-либо гарантии, но я кое-что прочитаю. Я больше беспокоюсь о том, что 'setTimeout' не делает то, что я ожидаю, хотя, как я полагался на него в прошлом, и теперь мне интересно, что еще может быть потенциально нарушено. – CupawnTae
@ Давид начальных экспериментов с одним' requestAnimationFrame 'показывать это работает большую часть времени, но не всегда. Я думаю, что второй 'requestAnimationFrame', вероятно, достигнет согласованности, но тогда я думаю, что это, вероятно, только потому, что вы в основном задерживаете достаточно долго, чтобы избежать условия гонки. Мне бы очень хотелось, чтобы что-то детерминированное ... – CupawnTae