前面的话

  与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开销

使用

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

requestID = requestAnimationFrame(callback); 

//控制台输出1和0
var timer = requestAnimationFrame(function(){console.log(0);
});
console.log(timer);//1

  cancelAnimationFrame方法用于取消定时器

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

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

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

兼容

  IE9-浏览器不支持该方法,可以使用setTimeout来兼容

【简单兼容】

if (!window.requestAnimationFrame) {requestAnimationFrame = function(fn) {setTimeout(fn, 17);};
}

【严格兼容】

if(!window.requestAnimationFrame){var lastTime = 0;window.requestAnimationFrame = function(callback){var currTime = new Date().getTime();var timeToCall = Math.max(0,16.7-(currTime - lastTime));var id  = window.setTimeout(function(){callback(currTime + timeToCall);},timeToCall);lastTime = currTime + timeToCall;return id;}
}

if (!window.cancelAnimationFrame) {window.cancelAnimationFrame = function(id) {clearTimeout(id);};
}

应用

  现在分别使用setInterval、setTimeout和requestAnimationFrame这三个方法制作一个简单的进制度效果

【1】setInterval

<div id="myDiv" style="background-color: lightblue;width: 0;height: 20px;line-height: 20px;">0%</div>
<button id="btn">run</button>
<script>
var timer;
btn.onclick = function(){clearInterval(timer);myDiv.style.width = '0';timer = setInterval(function(){if(parseInt(myDiv.style.width) < 500){myDiv.style.width = parseInt(myDiv.style.width) + 5 + 'px';myDiv.innerHTML =     parseInt(myDiv.style.width)/5 + '%';    }else{clearInterval(timer);}        },16);
}
</script>

【2】setTimeout

<div id="myDiv" style="background-color: lightblue;width: 0;height: 20px;line-height: 20px;">0%</div>
<button id="btn">run</button>
<script>
var timer;
btn.onclick = function(){clearTimeout(timer);myDiv.style.width = '0';timer = setTimeout(function fn(){if(parseInt(myDiv.style.width) < 500){myDiv.style.width = parseInt(myDiv.style.width) + 5 + 'px';myDiv.innerHTML =     parseInt(myDiv.style.width)/5 + '%';timer = setTimeout(fn,16);}else{clearTimeout(timer);}    },16);
}
</script>

【3】requestAnimationFrame

<div id="myDiv" style="background-color: lightblue;width: 0;height: 20px;line-height: 20px;">0%</div>
<button id="btn">run</button>
<script>
var timer;
btn.onclick = function(){myDiv.style.width = '0';cancelAnimationFrame(timer);timer = requestAnimationFrame(function fn(){if(parseInt(myDiv.style.width) < 500){myDiv.style.width = parseInt(myDiv.style.width) + 5 + 'px';myDiv.innerHTML =     parseInt(myDiv.style.width)/5 + '%';
            timer = requestAnimationFrame(fn);}else{cancelAnimationFrame(timer);}    });
}
</script>

转载自:https://www.cnblogs.com/xiaohuochai/p/5777186.html

转载于:https://www.cnblogs.com/create-and-orange/p/10849918.html

深入理解定时器系列第二篇——被誉为神器的requestAnimationFrame相关推荐

  1. 深入理解闭包系列第二篇——从执行环境角度看闭包

    前面的话 本文从执行环境的角度来分析闭包,先用一张图开宗明义,然后根据图示内容对代码进行逐行说明,试图对闭包进行更直观的解释 图示 说明 下面按照代码执行流的顺序对该图示进行详细说明 function ...

  2. 深入理解javascript函数系列第二篇——函数参数

    前面的话 javascript函数的参数与大多数其他语言的函数的参数有所不同.函数不介意传递进来多少个参数,也不在乎传进来的参数是什么数据类型,甚至可以不传参数.本文是深入理解javascript函数 ...

  3. 前端工程师技能之photoshop巧用系列第二篇——测量篇

    前端工程师使用photoshop进行的大量工作实际上是测量.本文是photoshop巧用系列第二篇--测量篇 测量信息 在网页制作中需要使用photoshop测量的信息分为两类,分别是尺寸信息和颜色信 ...

  4. 焱老师带你学习MYSQL系列 第二篇 (MYSQL 数据结构)

    相关系列链接 焱老师带你学习MYSQL系列 第六篇 (MYSQL是如何实现锁的) 焱老师带你学习MYSQL系列 第五篇 (MYSQL事务隔离级别是如何实现的) 焱老师带你学习MYSQL系列 第四篇 ( ...

  5. 阿里出品移动研发“神器” 阿里移动云系列第二篇|“移”步到位:一站式移动应用研发体系...

    摘要:2017杭州云栖大会阿里移动云峰会专场上,阿里巴巴高级技术专家小木带来一站式应用研发体系方面的演讲.本文主要以互联网的应用背景开始谈起,进而阐述了已拥有APP的企业在APP的生命周期中会遇见哪些 ...

  6. [游戏开发]Python打表工具系列 [第二篇] [打表流程描简述]

    [上一篇链接] [游戏开发]Python打表工具系列 [第一篇][IDE开发环境部署] VSCode Python环境调试_Little丶Seven的博客-CSDN博客 [前言] 第二篇文章是对流程的 ...

  7. 深入理解脚本化CSS系列第二篇——查询计算样式

    前面的话 元素的渲染结果是多个CSS样式博弈后的最终结果,这也是CSS中的C(cascade)层叠的含义.访问第一篇中的style属性只能获取行间样式,这通常来说,并不是我们想要的结果.本文将详细介绍 ...

  8. 深入理解定时器系列第三篇——定时器应用(时钟、倒计时、秒表和闹钟)

    前面的话 本文属于定时器的应用部分,分别用于实现与时间相关的四个应用,包括时钟.倒计时.秒表和闹钟.与时间相关需要用到时间和日期对象Date,详细情况移步至此 时钟 最简单的时钟制作办法是通过正则表达 ...

  9. 深入理解javascript选择器API系列第二篇——getElementsByClassName

    前面的话 既然有getElementById()和getElementsByTagName()方法,为什么没有getElementsByClassName()呢?id属性.标签名.class属性并没有 ...

最新文章

  1. CSS设计指南(读书笔记 - 选择器)
  2. 机器学习——Java调用sklearn生成好的Logistic模型进行鸢尾花的预测
  3. python百题百练 二级题目_CSDN Python语感百题(一)
  4. CSV出力ボタンラッパー(asp.net)[イベントの作り方に役立つ]
  5. 有趣的灵魂百里挑一,Linux同学你低下头干嘛,起来说下这个问题。
  6. 【暖*墟】#树链剖分# 树链剖分学习与练习
  7. TensorFlow中tf.ConfigProto()配置Sesion运算方式
  8. java算法:复合数据结构
  9. Js文字特效—文字段逐个变色循环
  10. 半小时漫画股票实战法观看记录,观看更新
  11. 扫码反馈,“码”上回复:二维码在业主意见反馈中的应用
  12. 电信联通提高手机补贴
  13. 自然语言处理中的Attention Model:是什么及为什么
  14. 64个 360 评估的提问样例
  15. iOS textfield 键盘弹出后不能切换中文键盘
  16. Java 导出Excel利用模版导出
  17. 简明 CSS2.1 参考手册
  18. 计算机发展史评课,【基层动态】课堂展风采 听评促成长—— 计算机与智能应用系听评课活动圆满结束...
  19. 数据库连接池 Connection Pool 是什么,做什么
  20. 安装dotnetfx3.5有感

热门文章

  1. C# 获取Get请求返回
  2. 控制台总是输出:xcode error: failed to attach to process ID 0
  3. SQL Server 日期转换格式
  4. datagrid嵌套和资源消耗
  5. [转]6个开源数据科学项目
  6. 读书笔记_打开量化投资的黑箱11
  7. 嵌入式工程师有发展前途吗?这是我看过最靠谱的回答
  8. 会mysql不会sql_不是吧,不会有人还不知道MySQL中具实用的SQL语句
  9. mysql error 1837_MySQL 主从复制错误1837
  10. 中key的用途_Python中的函数定义与参数使用