async/await 可通过 promise 封装 animationend 或 transitionend 事件实现等待动画完成,需区分事件类型、清理监听器、添加超时保护,并配合 requestanimationframe 确保触发。

在 JavaScript 中,async/await 本身不能直接“监听”动画结束,但可以结合 animationend 或 transitionend 事件,用 Promise 封装后实现“等待动画完成再继续执行”的效果。关键在于把事件驱动转为 Promise 驱动。
用 Promise 包装 animationend 事件
这是最常用也最可靠的方式:给目标元素的 animationend 创建一个一次性 Promise,在事件触发时 resolve,然后 await 它。
function waitForAnimation(el) {
return new Promise(resolve => {
const onEnd = () => {
el.removeEventListener('animationend', onEnd);
resolve();
};
el.addEventListener('animationend', onEnd);
});
}
使用示例:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
async function doSequentially() {
element.style.animation = 'slideIn 0.3s';
await waitForAnimation(element); // 等动画播完
console.log('动画结束了');
element.style.opacity = '0';
await waitForAnimation(element); // 如果这里用了 transition,需改用 transitionend
}
区分 animationend 和 transitionend
CSS 动画(@keyframes + animation)触发 animationend;而 CSS 属性过渡(如 opacity、transform 的变化)触发 transitionend。两者不能混用。
- 用
animation属性时,监听animationend - 用
transition属性时,监听transitionend,且建议加前缀或用getComputedStyle判断是否支持 - 若不确定,可同时监听两个事件,用
AbortController或标志位避免重复 resolve
处理多次动画或重复触发
如果元素可能被频繁触发动画(比如快速点击),要注意事件监听器未清除导致多次执行。上面的 waitForAnimation 已用 removeEventListener 清理,是安全的。但更健壮的做法是:
- 每次调用前先清理旧监听(尤其在重用函数时)
- 加超时保护,防止动画被取消或未触发:
Promise.race([waitForAnimation(el), timeout(2000)]) - 检查
event.animationName,避免响应其他动画(例如多个 animation 同时存在时)
配合 requestAnimationFrame 做更精确的启动
有时直接设 style.animation 可能因渲染时机问题导致 animationend 不触发(尤其在样式刚插入时)。推荐在下一帧开始动画:
async function safeAnimate(el, animationName) {
el.style.animation = 'none'; // 重置
await Promise.resolve(); // 确保样式已清空
requestAnimationFrame(() => {
el.style.animation = `${animationName} 0.3s`;
});
return waitForAnimation(el);
}Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










