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

RequestAnimationFrame无法停止日志输出的视频播放器进度条问题

视频暂停后requestAnimationFrame仍持续执行的问题及解决方法

问题描述

我在实现视频播放器进度条动画时遇到了异常:调用视频pause方法并执行cancelAnimationFrame后,requestAnimationFrame的回调函数仍在持续执行,控制台日志不停输出。

相关代码如下:

let stopId;

const playVideo = () =>{
    if(isPlaying){
        videoRef.current.pause()
        window.cancelAnimationFrame(stopId)
    }else{
        videoRef.current.play();
        window.requestAnimationFrame(calcTime)
    }
    setIsPlaying(!isPlaying)
}

const calcTime = () =>{
    stopId = window.requestAnimationFrame(calcTime)
    console.log('hey')
}

我做了额外测试,修改calcTime加入延时暂停逻辑:

const calcTime = () =>{           
    stopId = window.requestAnimationFrame(calcTime)
    console.log('hey')
    setTimeout(() => {
        videoRef.current.pause()
        window.cancelAnimationFrame(stopId)
        console.log('pause')
    }, 5000);
}

测试结果是先输出约300次hey才停止,之后又输出约300次pause。我想知道:视频暂停后requestAnimationFrame是不是真的还在运行?会不会引发性能问题?

问题原因

核心问题是每次调用requestAnimationFrame(calcTime)都会生成新的请求ID,但你只保存了最后一次的ID,之前的请求并未被取消:

  • 第一个代码中,calcTime递归调用自己时,每次都会把新的请求ID覆盖stopId。调用cancelAnimationFrame(stopId)只能取消最后一次的请求,而之前已经被调度的calcTime回调仍会执行,执行时又会发起新的请求,导致循环无法终止。
  • 第二个测试里,5秒内(按60fps计算约300次)requestAnimationFrame已经调度了几百次calcTime,每个calcTime都创建了一个setTimeout。即使取消了最后一次动画请求,已经排队的calcTime还是会执行,进而触发对应的setTimeout,所以会输出300次pause。

解决方案

要彻底终止动画循环,需要通过状态变量控制是否继续发起新的requestAnimationFrame请求,同时取消当前请求:

let stopId;
let shouldAnimate = false; // 新增状态变量控制动画循环

const playVideo = () =>{
    if(isPlaying){
        videoRef.current.pause()
        shouldAnimate = false; // 标记停止动画
        window.cancelAnimationFrame(stopId)
    }else{
        videoRef.current.play();
        shouldAnimate = true; // 标记开始动画
        window.requestAnimationFrame(calcTime)
    }
    setIsPlaying(!isPlaying)
}

const calcTime = () =>{
    if (!shouldAnimate) return; // 状态为停止时,不再发起新请求
    stopId = window.requestAnimationFrame(calcTime)
    console.log('hey')
    // 这里编写进度条更新逻辑
}

性能影响说明

如果放任未被取消的requestAnimationFrame持续运行,确实会造成不必要的性能消耗——浏览器会不断执行回调函数,占用主线程资源,可能导致页面卡顿。视频暂停后动画已无运行必要,这种无效执行完全可以避免。

内容的提问来源于stack exchange,提问作者john pear

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 15:15:36