使用requestAnimationFrame模拟实现setTimeout和setInterval rafTimeout 函数与 setTimeout 和 setInterval 用法基本一致接受以下参数fn延迟 delay ms 后要执行的函数delay可选延迟的毫秒数默认 0msinterval可选默认情况下 rafTimeout 等效于 setTimeout 功能如果要使用 setInterval 功能则需传入第三个参数interval: true返回值用于取消 rafTimeoutraf: { id: number }取消 rafTimeout 定时器cancelRaf(raf)cancelAnimationFrame(raf.id)在线预览/** * 使用 requestAnimationFrame 实现的延迟 setTimeout 或间隔 setInterval 调用函数 * * param {Function} fn 要执行的函数 * param {number} [delay 0] 延迟的时间单位为 ms默认为 0表示不延迟立即执行 * param {boolean} [interval false] 是否间隔执行如果为 true则在首次执行后以 delay 为间隔持续执行 * returns {{ id: number }} 返回一个对象包含一个 id 属性该 id 为 requestAnimationFrame 的调用 ID可用于取消动画帧 */ export type AnimationFrameID { id: number } export function rafTimeout(fn: Function, delay: number 0, interval: boolean false): AnimationFrameID { let start: number | null null // 记录动画开始的时间戳 function timeElapse(timestamp: number) { // 定义动画帧回调函数 /* timestamp参数与 performance.now() 的返回值相同它表示 requestAnimationFrame() 开始去执行回调函数的时刻 */ if (!start) { // 如果还没有开始时间则以当前时间为开始时间 start timestamp } const elapsed timestamp - start if (elapsed delay) { try { fn() // 执行目标函数 } catch (error) { console.error(Error executing rafTimeout function:, error) } if (interval) { // 如果需要间隔执行则重置开始时间并继续安排下一次动画帧 start timestamp raf.id requestAnimationFrame(timeElapse) } } else { raf.id requestAnimationFrame(timeElapse) } } // 创建一个对象用于存储动画帧的 ID并初始化动画帧 const raf: AnimationFrameID { id: requestAnimationFrame(timeElapse) } return raf } /** * 用于取消 rafTimeout 函数 * * param {{ id: number }} raf - 包含请求动画帧 ID 的对象该 ID 是由 requestAnimationFrame 返回的 * 该函数旨在取消之前通过 requestAnimationFrame 请求的动画帧 * 如果传入的 raf 对象或其 id 无效则会打印警告 */ export function cancelRaf(raf: AnimationFrameID): void { if (raf raf.id typeof raf.id number) { cancelAnimationFrame(raf.id) } else { console.warn(cancelRaf received an invalid id:, raf) } }