可能你还没见过这个东西是个啥,其实他就是类似于setTimeout和setInterval,然而它与setTimeout和setInterval又有所不同,requestAnimationFrame不需要设置时间间隔。这有什么好处呢?requestAnimationFrame有何神奇之处?本文将详细介绍HTML5新增的定时器requestAnimationFrame。

计时器一直是javascript动画的核心技术。而编写动画循环的关键是要知道延迟时间多长合适。一方面,循环间隔必须足够短,这样才能让不同的动画效果显得平滑流畅;另一方面,循环间隔还要足够长,这样才能确保浏览器有能力渲染产生的变化。

大多数电脑显示器的刷新频率是60Hz,大概相当于每秒钟重绘60次。大多数浏览器都会对重绘操作加以限制,不超过显示器的重绘频率,因为即使超过那个频率用户体验也不会有提升。因此,最平滑动画的最佳循环间隔是1000ms/60,约等于16.6ms。

而setTimeout和setInterval的问题是,它们都不精确。它们的内在运行机制决定了时间间隔参数实际上只是指定了把动画代码添加到浏览器UI线程队列中以等待执行的时间。如果队列前面已经加入了其他任务,那动画代码就要等前面的任务完成后再执行。

requestAnimationFrame采用系统时间间隔,保持最佳绘制效率,不会因为间隔时间过短,造成过度绘制,增加开销;也不会因为间隔时间太长,使用动画卡顿不流畅,让各种网页动画效果能够有一个统一的刷新机制,从而节省系统资源,提高系统性能,改善视觉效果。

特点

  • 【1】requestAnimationFrame会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率
  • 【2】在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的CPU、GPU和内存使用量
  • 【3】requestAnimationFrame是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU开销
  • 【4】requestAnimationFrame可以在某些时候解决setTimeout和setInterval的bug,传统定时器在页面tab切换时候,定时器会进入一个假死状态,比如你电脑开了两个窗口,首先你打开有定时器的页面,然后定时器开始执行,假设每秒i+1,当i=10时候你切换到别的tab窗口,隔了一段时间看,i继续从=10开始累加。。。

使用

requestAnimationFrame的用法与settimeout很相似,只是不需要设置时间间隔而已。requestAnimationFrame使用一个回调函数作为参数,这个回调函数会在浏览器重绘之前调用。它返回一个整数,表示定时器的编号,这个值可以传递给cancelAnimationFrame用于取消这个函数的执行

1
2
3
4
5
var timer = requestAnimationFrame(function(){
    console.log(0);
});
console.log(timer);
//结果1和0

上面这段代码其中结果1则是requestAnimationFrame返回值,执行一遍返回1,如此类推,你可能疑惑为什么console.log(timer);中的timer没有加()也能执行,这得回到文章头部说到的你可以理解为requestAnimationFrame就是个定时器,定时器自然不需要手动去触发执行

cancelAnimationFrame方法用于取消定时器

1
2
3
4
5
//控制台什么都不输出
var timer = requestAnimationFrame(function(){
    console.log(0);
});
cancelAnimationFrame(timer);

也可以直接使用返回值进行取消

1
2
3
4
var timer = requestAnimationFrame(function(){
    console.log(0);
});
cancelAnimationFrame(1);

示例,解决传统定时器bug

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
   * 倒计时循环
   * @private
   */
  _CountDownLoop() {
    var currStemp = new Date();
    currStemp = new Date(currStemp.getTime() + this.offset);
    //如果结束时间戳减去当前时间时间戳小于等于0则设置倒计时结束标识为true
    if (this.endStemp.getTime() - currStemp.getTime() <= 0) {
      this.isEnd = true;
    }
    //如果结束则调用结束回调
    if (this.isEnd === true) {
      // console.log('countdown end');
      this.endcallback.apply(this, [this.endurl]);
    } else {
      this._render(currStemp);
      var that = this;
      requestAnimationFrame(function() {
        that._CountDownLoop();
      });
    }
  }

小结

上面示例中我们可以看到,通过requestAnimationFrame不断的自己调用自己,实现高频度刷新倒计时,从而解决了页面切换窗口等传统setTimeout和setInterval假死问题。

神奇的requestAnimationFrame解决传统定时器bug的更多相关文章

  1. Java多线程与并发库高级应用-传统定时器技术回顾

    传统定时器技术回顾(jdk1.5以前) public class TraditionalTimerTest { static int count = 0; public static void mai ...

  2. 文《左右c++与java中国的垃圾问题的分析与解决》一bug分析

    文<左右c++与java中国的垃圾问题的分析与解决>一bug分析 DionysosLai(906391500@qq.com) 2014/10/21 在前几篇一博客<关于c++与jav ...

  3. JAVA多线程提高一:传统线程技术&传统定时器Timer

    前面我们已经对多线程的基础知识有了一定的了解,那么接下来我们将要对多线程进一步深入的学习:但在学习之前我们还是要对传统的技术进行一次回顾,本章我们回顾的则是:传统线程技术和传统的定时器实现. 一.传统 ...

  4. 花了5天时间,终于解决了一个bug,心情非常愉快,憋了这么久,不吐不快

    http://www.cnweblog.com/fly2700/archive/2011/12/06/318916.html (转载) 花了5天时间,终于解决了一个bug,心情非常愉快,憋了这么久,不 ...

  5. 听说”双11”是这么解决线上bug的

    听说"双11"是这么解决线上bug的 --Android线上热修复的使用与原理 预备知识和开发环境 Android NDK编程 AndFix浅析 Android线上热修复的原理大同 ...

  6. 华为SDN:解决传统网络3大问题

    转:http://mp.ofweek.com/tele/a145613326756 科技潮人 2013-08-05 14:20 传统网络之困 互联网爆炸式增长,除了规模和发展速度远超之前所有曾出现的数 ...

  7. 搜索框+ 定时器+Bug解决

    定时器 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8 ...

  8. 解决.net定时器在iis7上不执行问题

    今天第一次在博客园发帖,以前一直在潜水,在这里也是学了不少东西.感谢各位园友 废话不多说,这也是我工作中遇到的问题: protected void Application_Start(object s ...

  9. iOS 解决一个复杂bug 之 计分卡

    由于该模块界面和业务逻辑都很复杂,并且整个界面设计和业务逻辑都在ViewController(下面简称为VC)里面完成.该VC共有3000多行,一个函数几百张的也有.所以,解决起来真是头疼. 1. 问 ...

随机推荐

  1. SpringMVC进行Ajax请求页面显示乱码

    最近在项目的使用过程中发现在springmvc的项目中,使用返回页面的请求方式,数据都能正常显示,但是对于ajax的请求,始终显示乱码. 首先第一种是因为我们在web.xml中配置了spring的字符 ...

  2. SSL扫描工具

    工具: sslciphercheck sslscan sslciphercheck.exe -h ip -p 443 有些IP会报错:

  3. vue插槽的使用

    一.插槽的基本使用 二.具名插槽的使用 三.编译作用域的例子 四.作用域插槽 一.插槽的基本使用     1.插槽的基本使用<slot></slot>     2.插槽的默认值 ...

  4. 本地cmd连接远程mysql数据库

    一.登录远程mysql 输入mysql -h要远程的IP地址 -u设置的MySQL用户名 -p登录用户密码 例如:mysql -h 192.168.1.139 -u root -p dorlocald ...

  5. CF div2

    这是一道二进制思维题: 将所有数字列成二进制形式,然后找出最大的一位“1”出现一次的位数: 然后把这个数提到前面,其他照常输出即可 #include<bits/stdc++.h> usin ...

  6. [lua]紫猫lua教程-命令宝典-L1-01-10. 自定义函数

    L1[function]01. 定义与调用函数 函数的定义 和概念 没什么可说的 lua的函数声明和调用是有先后顺序的  先声明后调用 函数就是变量的一种 所以可以自由的把函数在变量间相互赋值 不过注 ...

  7. Iris请求方式和数据返回类型

    1. Iris起服务 package main import "github.com/kataras/iris" func main() { //1.创建app结构体对象 app ...

  8. python记之Hello world!

    ________________________________该动手实践了. 数和表达式 交互式Python解释器可用作功能强大的计算器. 除法运算的结果为小数,即浮点数(float或floatin ...

  9. 95. 不同的二叉搜索树 II、96. 不同的二叉搜索树

    95 Tg:递归 这题不能算DP吧,就是递归 一个问题:每次的树都要新建,不能共用一个根节点,否则下次遍历对根左右子树的改动会把已经放进结果数组中的树改掉.. class Solution: def ...

  10. thinkphp中 model(模型)的使用

    首先:有三个数据表 现在用命令行建立它们的模型 php think make:model admin/Class php think make:model index/Teacher