# 动画控制的另一种技术



> 在 HTML5 的时代里我们可以通过 css3 的 animation 和 kerframes 配合使用动画；也可以使用 css 的 transform 控制动画；在 JS 里面我们通常用 setTimeout 和 setInterval 来控制动画时间。setTimeout 和 setInterval 对于控制动画时间不是很准确，因为它是靠电脑的刷新频率。并且当浏览器切换到其他页面或者最小化的时候动画还在执行并不会停止，显然是在做一些无用功。接下来要介绍一个新的特性，并且主流浏览器都对他进行了支持。



### requestAnimationFrame

来看看 [MDN](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestAnimationFrame) 对它的介绍

> window.requestAnimationFrame() 方法告诉浏览器您希望执行动画并在浏览器在下一次重绘之前调用指定的函数来更新动画。该方法使用一个回调函数作为参数，这个回调函数会在浏览器重绘之前调用。
>
> 注意：若您想在下次重绘时产生另一个动画画面，您的回调例程必须调用 requestAnimationFrame()
>
> 当你需要更新屏幕画面时就可以调用此方法。在浏览器下次重绘前执行回调函数。回调的次数通常是每秒60次，但大多数浏览器通常匹配 W3C 所建议的刷新频率。在大多数浏览器里，当运行在后台标签页或者隐藏的<iframe>里时，`requestAnimationFrame()` 会暂停调用以提升性能和电池寿命。
>
> 回调函数会被传入一个参数，[`DOMHighResTimeStamp`](https://developer.mozilla.org/zh-CN/docs/Web/API/DOMHighResTimeStamp)，指示当前被 `requestAnimationFrame()` 排序的回调函数被触发的时间。即使每个回调函数的工作量的计算都花了时间，单个帧中的多个回调也都将被传入相同的时间戳。该时间戳是一个十进制数，单位毫秒，最小精度为1ms(1000μs)。



#### 语法

```javascript
window.requestAnimationFrame(callback)
```

参数：

callback 一个指定回调函数形式的参数。该函数在下次重绘动画时调用。这个回调函数只有一个参数 ： **DOMHighResTimeStamp** ，指示 requestAnimationFrame() 开始触发回调函数的当前时间 （preformance.now() 返回的时间）

返回值：

一个 **long** 整数，请求 ID，是回调列表中的唯一标识。是个非零值。后续可以作为 **window.cancelAnimationFrame()** 以取消回调函数。







#### Demo

```html
<html>
  <head>
    <meta charset="utf-8">
    <title>动画</title>
  </head>
  <body>
    <div id="test" style="width:1px;height: 17px;background: #0f0;">0%</div>
    <input type="button" value="Run" id="run" >
  </body>
  <script>
    window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.mzRequestAnimationFrame;
    var start = null;
    var ele = document.getElementById("test");
    var progress =0;
    function step(timestamp){
      console.log("step" + timestamp);
      progress += 1;
      ele.style.width = progress + "%";
      ele.innerHTML = progress + "%";
      if (progress < 100) {
        requestAnimationFrame(step);
      }
    }

    requestAnimationFrame(step);
    document.getElementById("run").addEventListener("click", function(){
      console.log("run");
      ele.style.width = "1px";
      progress = 0;
      requestAnimationFrame(step);
    },false);
  </script>
</html>
```





















