You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Web Animation API:animation.cancel()后animation.finished Promise始终pending

Web Animation API cancel()后finished Promise pending问题解决方案

调用animation.cancel()后,对应的finished Promise不会保持pending,而是会抛出AbortError并reject。你的代码中依赖Promise.all([ani && ani.finished])等待上一个动画完成,但未处理reject情况,导致Promise链卡住,后续动画无法执行。

核心原因

  • 动画正常结束时,finished Promise会resolve;调用cancel()强制终止动画时,finished Promise会直接reject,而非持续pending。
  • 原代码未处理reject分支,导致Promise.all的回调永远不会触发,新动画无法创建。

解决方案

根据你“点击按钮时,等待上一个动画结束后切换到新元素执行动画”的需求,提供两种调整方案:

方案1:等待上一个动画完成(或处理cancel)后启动新动画

使用async/await简化Promise逻辑,同时捕获cancel导致的reject,避免阻塞:

let btn = document.querySelector("#btn");
let element = null;
let currentId = 1;
let ani = null;
let transformArray = [
  {transform: 'translate(0px, 0px)'},
  {transform: 'translate(100px, 0px)'}
];

btn.onclick = async function () {
  // 处理上一个动画
  if (ani) {
    try {
      // 等待上一个动画正常完成
      await ani.finished;
    } catch (err) {
      // 捕获cancel导致的reject,避免后续逻辑阻塞
      console.log('上一个动画被取消', err);
    } finally {
      // 可选:取消动画以重置元素状态(如果不需要保持最终状态)
      ani.cancel();
    }
  }

  // 切换到当前元素并启动新动画
  element = document.querySelector("#icon" + currentId);
  ani = element.animate(transformArray, {
    duration: 1000,
    fill: "forwards",
    easing: "ease"
  });

  // 更新元素ID循环
  currentId++;
  if (currentId === 4) {
    currentId = 1;
  }
};

方案2:立即取消上一个动画并启动新动画

如果不需要等待上一个动画完成,直接切换元素执行动画:

let btn = document.querySelector("#btn");
let element = null;
let currentId = 1;
let ani = null;
let transformArray = [
  {transform: 'translate(0px, 0px)'},
  {transform: 'translate(100px, 0px)'}
];

btn.onclick = function () {
  // 立即取消上一个动画(如果存在)
  ani?.cancel();

  // 启动当前元素的动画
  element = document.querySelector("#icon" + currentId);
  ani = element.animate(transformArray, {
    duration: 1000,
    fill: "forwards",
    easing: "ease"
  });

  // 更新元素ID循环
  currentId++;
  if (currentId === 4) {
    currentId = 1;
  }
};

关键说明

  • fill: "forwards"会让元素保持动画的最终状态,不需要在finish后调用cancel,除非你需要重置元素到初始状态。
  • 当必须调用cancel()时,一定要捕获finished Promise的reject,否则会阻塞后续Promise链的执行。

内容的提问来源于stack exchange,提问作者吴自强

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 21:54:51