requestAnimationFrame
这里会说下
requestAnimationFrame的由来,以及为什么会出现它。同时也会横向对比下定时器以及延时器
早期的动画
动画是一个持续的过程。早期的时候动画都是通过定时器来实现的。看如下代码
(function() {
 function updateAnimations() { 
 doAnimation1(); 
 doAnimation2(); 
 // 其他任务
 } 
 setInterval(updateAnimations, 100); 
})();
- 一般的计算器显示器的屏幕刷新频率是60HZ,这就意味着是每秒要绘制60次。大多数浏览器都会显示绘制频率。
 - 为了实现动画效果过渡平滑最佳的重绘间隔大约17/毫秒。以这个速度重绘可以实现最佳的滑动效果。
 - 但是即使是这样依然无法保证能平滑过度。因为延时器/定时器的执行的时机不定。虽然可以设置执行时间。即使将延时任务添加到队列中也无法保证能立马执行。这取决于上一个任务或是同步任务执行的时间长度
 - 从js层面无法得知浏览器的绘制时机。所以函数
 requestAnimationFrame就出现了
函数requestAnimationFrame
1. 执行时机
- 在每次浏览器重绘之前执行
 
2. 使用方法
- 函数
requestAnimationFrame只允许传递一个参数。而且参数必须是一个函数 - 参数函数会被加入到队列。在每次浏览器绘制之前将队列中的函数进行执行
 - 每添加一次再下次绘制执行后,需要再次添加
 
function updateProgress() {
 var div = document.getElementById("status"); 
 div.style.width = (parseInt(div.style.width, 10) + 5) + "%"; 
 if (div.style.left != "100%") { 
 requestAnimationFrame(updateProgress); 
 } 
} 
requestAnimationFrame(updateProgress);
3. 如何取消
在全局中提供了函数
cancelAnimationFrame. 可以通过函数进行取消。大致的原理跟延时器/ 定时器保持一致
- 在函数
requestAnimationFrame将函数加入队列后,会返回一个id(可以将id理解为队列的位置)。可以通过执行函数cancelAnimationFrame来进行取消 
let requestID = window.requestAnimationFrame(() => {
 console.log('Repaint!'); 
}); 
window.cancelAnimationFrame(requestID);
通过函数requestAnimationFrame进行节流处理
let enabled = true;
function expensiveOperation() { 
 console.log('Invoked at', Date.now()); 
} 
window.addEventListener('scroll', () => { 
 if (enabled) { 
 enabled = false; 
 window.requestAnimationFrame(expensiveOperation); 
 window.setTimeout(() => enabled = true, 50); 
 } 
});