В вашем случае я чувствую, что Promise - это путь.
По моему собственному эмпирическому правилу (будьте осторожны, он самоуверенный):
- Используйте обещание, когда вам нужнодля выполнения асинхронных операций последовательно .
- Используйте функцию генератора, когда вам нужно сгенерировать результат , когда вам это нужно.
В вашем фрагментевсе, что вам нужно сделать, это запустить анимацию последовательно , а не , когда вам это нужно.
Кроме того, вы заметите, что у вас есть несколько функций, которые зависят от текущего состояния (результата) одной переменной (т. Е. iterator
).Плохо в этом то, что когда между вашей последовательностью возникает ошибка, вам потребуется больше времени и усилий для отладки ситуации, потому что одно изменение в одной функции может повлиять на другие функции.У вас также есть глобальный transitionend
прослушиватель событий, который с первого взгляда весьма потребляет.
Короче говоря, используя функции генератора, последовательность последовательных операций трудно понять.
Подходниже используется async / await.Изменяются только методы Sequence
и nextSequence
(поясните комментарии внутри).Каждая операция содержится в своей области видимости.Уменьшается зависимость от глобальных переменных:
(Извините, я отформатировал код в соответствии со своим стилем кода, когда писал их)
const Root = document.documentElement;
const gRoot = window.getComputedStyle(Root);
const moving = [
{
T: -30,
L: 0
},
{
T: 0,
L: +30
},
{
T: +30,
L: 0
},
{
T: 0,
L: -30
}
];
let RotateDeg = 0;
let RotateMov = 0;
let posT = parseInt(gRoot.getPropertyValue('--PosT'));
let posL = parseInt(gRoot.getPropertyValue('--PosL'));
function F_1(){
posT += moving[RotateMov].T;
posL += moving[RotateMov].L;
Root.style.setProperty('--PosT', posT + 'px');
Root.style.setProperty('--PosL', posL + 'px');
}
function T_L(){
RotateMov = (RotateMov + 3) % 4;
RotateDeg -= 90;
Root.style.setProperty('--turn', RotateDeg + 'deg');
}
function T_R(){
RotateMov = (RotateMov + 1) % 4;
RotateDeg += 90;
Root.style.setProperty('--turn', RotateDeg + 'deg');
}
function R_0(){
RotateMov = 0;
RotateDeg = 0;
Root.style.setProperty('--turn', RotateDeg + 'deg');
}
function disableButtons(OnOff){
Bt_Tab_A.disabled = OnOff
Bt_Tab_B.disabled = OnOff
}
async function Sequence(Tab_fct){
// Disable buttons before start
disableButtons(true);
for (let fct of Tab_fct)
// Run the animation one by one
await nextSequence(fct);
// Reenable buttons before end
disableButtons(false);
}
function nextSequence(fct){
return new Promise(res => {
// Move event listener here so that they dont depend on a global one.
// Use { once: true } to run this callback only once
window.addEventListener('transitionend', res, { once: true });
// Run the animation
fct();
})
}
Bt_Tab_A.onclick = () => {
Sequence([F_1, T_L, F_1, T_R, F_1, T_R, F_1, F_1, T_R, F_1, F_1, T_R, F_1, R_0]);
}
Bt_Tab_B.onclick = () => {
Sequence([ T_L, F_1, T_R, F_1, T_R, F_1, T_R, F_1, R_0 ]);
}
:root {
--turn : 0deg;
--PosT : 110px;
--PosL : 90px;
}
#robot {
font-size : 16px;
width : 30px;
height : 30px;
background-color: aqua;
text-align : center;
line-height : 1.8em;
transition : all .5s linear;
transform : rotate( var(--turn) );
position:fixed;
top : var(--PosT);
left: var(--PosL);
}
<div id="robot">R</div>
<button id="Bt_Tab_A">Sequence A</button>
<button id="Bt_Tab_B">Sequence B</button>