В этом примере шар (круг SVG) создается каждый раз, когда указатель мыши наводится на серый квадрат. К мячу добавляется анимация, идущая сверху слева направо, а затем запускается.
Иногда, по крайней мере, в последней версии Chrome, мяч создается, но анимация не отображается до тех пор, пока не произойдет следующее событие. Где я ошибаюсь?
function anim() {
const circ = document.createElementNS("http://www.w3.org/2000/svg", "circle");
circ.setAttribute("class", "ball");
circ.setAttribute("cx", 0);
circ.setAttribute("cy", 0);
const anim = document.createElementNS("http://www.w3.org/2000/svg", "animateTransform");
anim.setAttribute("attributeName", "transform");
anim.setAttribute("type", "translate");
anim.setAttribute("begin", "indefinite");
anim.setAttribute("from", "0,0");
anim.setAttribute("to", "300,300");
anim.setAttribute("dur", "2s");
anim.setAttribute("repeatCount", "1");
anim.addEventListener("endEvent", (e) => {
e.target.parentElement.remove();
});
circ.append(anim);
test.append(circ);
anim.beginElement();
}
const test = document.querySelector("#test");
test.addEventListener("mouseenter", anim);#test {
background-color: lightgray;
height: 300px;
width: 300px;
}
.ball {
fill: black;
r: 10px;
}<svg id = "test" />


![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Похоже, что проблемы возникают из-за того, что анимация активируется до того, как SVG был перерисован.
В этом фрагменте добавление элементов в SVG начинается после того, как система получит возможность перерисовать измененный SVG с его новыми атрибутами.
<!DOCTYPE html>
<html>
<head>
<style>
#test {
background-color: lightgray;
height: 300px;
width: 300px;
}
.ball {
fill: black;
r: 10px;
}
</style>
</head>
<body>
<svg id = "test" />
<script>
function anim() {
const circ = document.createElementNS("http://www.w3.org/2000/svg", "circle");
circ.setAttribute("class", "ball");
circ.setAttribute("cx", 0);
circ.setAttribute("cy", 0);
const anim = document.createElementNS("http://www.w3.org/2000/svg", "animateTransform");
anim.setAttribute("attributeName", "transform");
anim.setAttribute("type", "translate");
anim.setAttribute("begin", "indefinite");
anim.setAttribute("from", "0,0");
anim.setAttribute("to", "300,300");
anim.setAttribute("dur", "2s");
anim.setAttribute("repeatCount", "1");
anim.addEventListener("endEvent", (e) => {
e.target.parentElement.remove();
});
requestAnimationFrame(function() {
circ.append(anim);
test.append(circ);
anim.beginElement();
});
}
const test = document.querySelector("#test");
test.addEventListener("mouseenter", anim);
</script>
</body>
</html>@Кайидо, это интересно. Я не видел проблем с requestAnimationFrame и думал, что он, по сути, имеет тот же эффект перекомпоновки - это означает, что я не полностью уловил порядок событий, я думаю!
Ни один РАФ не срабатывает до следующей окраски и до пересчета. Здесь даже простой setTimeout() тоже работает, поэтому я не уверен на 100%, что происходит, и у меня нет времени разбираться. Тем не менее, синхронный запуск перекомпоновки обычно является наиболее надежным решением, поскольку все асинхронные решения могут фактически работать, потому что произошло что-то еще, и не факт, что это что-то еще будет происходить всегда. Но в любом случае, если бы кто-то смог открыть проблему, это было бы хорошо.
@Кайидо, спасибо за объяснение. Теперь я немного прояснился и согласен, что следует использовать определенную принудительную синхронную перекомпоновку или, возможно, двойной rAF, как, например. обсуждается в stackoverflow.com/questions/75527696/…
Запуск перекомпоновки (например,
document.body.offsetWidth;) также работает и кажется более надежным, поскольку rAF сработает перед следующей перерисовкой и, возможно, перед следующим пересчетом.