rafTimeout 函数与 setTimeout 和 setInterval 用法基本一致!
接受参数:
fn:延迟 delay ms 后要执行的函数
delay(可选):延迟的毫秒数,默认 0ms
interval(可选):默认情况下 rafTimeout 等效于 setTimeout 功能,如果要使用 setInterval 功能,则需传入第三个参数(interval: true)
返回值(用于取消 rafTimeout):
- raf: { id: number }
取消 rafTimeout 定时器:
cancelRaf(raf)
cancelAnimationFrame(raf.id)
/**
* 使用requestAnimationFrame实现的延迟setTimeout或间隔setInterval调用函数。
*
* @param fn 要执行的函数。
* @param delay 延迟的时间,单位为ms,默认为0,表示不延迟立即执行。
* @param interval 是否间隔执行,如果为true,则在首次执行后,以delay为间隔持续执行。
* @returns 返回一个对象,包含一个id属性,该id为requestAnimationFrame的调用ID,可用于取消动画帧。
*/
export function rafTimeout(fn: Function, delay = 0, interval = false): object {
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)
}
}
interface AnimationFrameID {
id: number
}
// 创建一个对象用于存储动画帧的ID,并初始化动画帧
const raf: AnimationFrameID = {
id: requestAnimationFrame(timeElapse)
}
return raf
}
/**
* 用于取消 rafTimeout 函数
*
* @param raf - 包含请求动画帧ID的对象。该ID是由requestAnimationFrame返回的。
* 该函数旨在取消之前通过requestAnimationFrame请求的动画帧。
* 如果传入的raf对象或其id无效,则会打印警告。
*/
export function cancelRaf(raf: { id: number }): void {
if (raf && raf.id && typeof raf.id === 'number') {
cancelAnimationFrame(raf.id)
} else {
console.warn('cancelRaf received an invalid id:', raf)
}
}