使用 async 完成一个 CSS 动画队列
项目需求:动画效果按照规定的顺序执行,演示地址
const first = box => {
return new Promise(callback => {
box.style.transform = 'translate(200px, 0) rotate(90deg)';
setTimeout(() => {
callback();
}, 1000)
})
}
const second = box => {
return new Promise(callback => {
box.style.transform = 'translate(200px, 200px) rotate(180deg)';
setTimeout(() => {
callback();
}, 1000)
})
}
const third = box => {
return new Promise(callback => {
box.style.transform = 'translate(0, 200px) rotate(270deg)';
setTimeout(() => {
callback();
}, 1000)
})
}
const fourth = box => {
return new Promise(callback => {
box.style.transform = 'translate(0, 0) rotate(360deg)';
setTimeout(() => {
callback();
}, 1000)
})
}
const run = async () => {
let box = document.querySelector('.box');
await first(box);
await second(box);
await third(box);
await fourth(box);
box.style.transform = 'rotate(0)';
running = false;
};
let running = false;
document.querySelector('button').onclick = function(){
if(!running) run();
running = true;
}
原理
在 async 方法中,在 promise 对象前添加 await 关键字,会等待 promise 的状态完成后才继续执行。没有 await 关键字的语句,会按照正常的顺序执行。所以上面 run() 方法的执行顺序是:
- 1. 获取 dom
- 2. 执行 first()
- 3. 等待 first() 完成,执行 second()
- 4. 等待 second() 完成,执行 third()
- 5. 等待 third() 完成,执行 fourth()
- 6. 等待 fourth() 完成,把 dom 旋转角度复位
- 7. running 赋值为 false
爬坑
发现 transform 的一个坑:当 transform 在页面加载时就执行,首次执行会没有动画效果,需要触发事件才能真正执行,也可放到 setTimeout 中执行。