我有特殊的节能技巧,处理事件的时候我会装作四处看风景
2014-03-22 18:58
330 查看
本文主要讲的是基于requestAnimationFrame的函数节流技巧。
如果你还不熟悉requestAnimationFrame,你可以看一下msdn上的这篇文章基于脚本的动画的计时控制。
requestAnimationFrame有助于我们创建丝滑柔顺的动画,同时也有利于优化性能和节约电能。然而我们创建的很多动画都要依赖于DOM事件,像mousemove,resize,scroll等这些事件调用函数的频率却远远比浏览器重绘的频率快,这就造成了和使用setTimeout或setInterval创建动画相似的弊端。举个栗子,比如在一个画布里,我们要创建一个跟随鼠标雪花不断飘落的动画效果。鼠标每移动一下,我们就通过科赫曲线绘制若干随机大小雪花来模拟新产生的雪花。使用科赫曲线画雪花无疑是密集型计算,而mousemove每秒触发上百次,结果就是看到巨卡无比的动画。当然这个方法有很多需要优化的地方,比如你可以缓存一个雪花,用drawImage来替换每次重新绘制路径,然后通过放缩来产生不同大小的雪花;或者用webgl来加速……本文就聚焦于优化mousemove事件。
先做个试验,看看mousemove事件每秒触发多少次。
用浏览器打开这个HTML文档,鼠标晃动个一两秒,打开控制台,在我这里显示的是125。
结果就是在短短的一秒内listener函数调用了高达125次,远超浏览器每秒60次的重绘频率。
下面来看一个特殊的节流函数。
我们先来看这个节流函数对优化mousemove事件的作用,然后再解释它是怎么工作的。
重复一样的步骤,控制台上这次显示的是61,接近完美的数字。
现在我们来看看throttle函数的原理。用一个比喻来阐释一下:你要调戏一下KFC,重复给宅急送打电话订餐。假设电话老是占线,你平均1分钟才能打进一次。一个固定的快递负责你们小区。如果客服发现快递还没送到你又打电话进来,客服想这个王八蛋又来催了,直接就挂了你的电话。结果就是一小时你最多只能拿到60份。如果快递1分钟内送不到你手上,你连60份也拿不到。如果快递30秒就送到了,你电话1分钟才能打进一次,也只能拿到60份。你打电话就好比throttle被调用,无论被调用的有多快,requestAnimationFrame只能以接近60fps的速度调用你给定的函数。如果你的给定函数还要执行很长时间,那么一秒内它总共执行的次数就少于60次;如果你给定的函数执行很快,一秒内总执行次数也不会多于60。
如果你还不熟悉requestAnimationFrame,你可以看一下msdn上的这篇文章基于脚本的动画的计时控制。
requestAnimationFrame有助于我们创建丝滑柔顺的动画,同时也有利于优化性能和节约电能。然而我们创建的很多动画都要依赖于DOM事件,像mousemove,resize,scroll等这些事件调用函数的频率却远远比浏览器重绘的频率快,这就造成了和使用setTimeout或setInterval创建动画相似的弊端。举个栗子,比如在一个画布里,我们要创建一个跟随鼠标雪花不断飘落的动画效果。鼠标每移动一下,我们就通过科赫曲线绘制若干随机大小雪花来模拟新产生的雪花。使用科赫曲线画雪花无疑是密集型计算,而mousemove每秒触发上百次,结果就是看到巨卡无比的动画。当然这个方法有很多需要优化的地方,比如你可以缓存一个雪花,用drawImage来替换每次重新绘制路径,然后通过放缩来产生不同大小的雪花;或者用webgl来加速……本文就聚焦于优化mousemove事件。
先做个试验,看看mousemove事件每秒触发多少次。
<!DOCTYPE html> <html> <head> <title></title> </head> <body> <script> var time = [], i = 0; function listener() { time[time.length] = Date.now(); if (time[time.length - 1] - time[0] > 1000) { console.log(i); document.removeEventListener("mousemove", listener); } i++; } document.addEventListener("mousemove", listener); </script> </body> </html>
用浏览器打开这个HTML文档,鼠标晃动个一两秒,打开控制台,在我这里显示的是125。
结果就是在短短的一秒内listener函数调用了高达125次,远超浏览器每秒60次的重绘频率。
下面来看一个特殊的节流函数。
function throttle(fn) { var handle; return function () { var context = this, args = arguments; cancelAnimationFrame(handle); handle = requestAnimationFrame(function () { fn.apply(context, args); handle = null; }); }; }
我们先来看这个节流函数对优化mousemove事件的作用,然后再解释它是怎么工作的。
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<script>
var time = [], i = 0, lis = throttle(listener);
document.addEventListener("mousemove", lis);
function throttle(fn) { var handle; return function () { var context = this, args = arguments; cancelAnimationFrame(handle); handle = requestAnimationFrame(function () { fn.apply(context, args); handle = null; }); }; }
function listener() {
time[time.length] = Date.now();
if (time[time.length - 1] - time[0] > 1000) {
console.log(i);
document.removeEventListener("mousemove", lis);
}
i++;
}
</script>
</body>
</html>
重复一样的步骤,控制台上这次显示的是61,接近完美的数字。
现在我们来看看throttle函数的原理。用一个比喻来阐释一下:你要调戏一下KFC,重复给宅急送打电话订餐。假设电话老是占线,你平均1分钟才能打进一次。一个固定的快递负责你们小区。如果客服发现快递还没送到你又打电话进来,客服想这个王八蛋又来催了,直接就挂了你的电话。结果就是一小时你最多只能拿到60份。如果快递1分钟内送不到你手上,你连60份也拿不到。如果快递30秒就送到了,你电话1分钟才能打进一次,也只能拿到60份。你打电话就好比throttle被调用,无论被调用的有多快,requestAnimationFrame只能以接近60fps的速度调用你给定的函数。如果你的给定函数还要执行很长时间,那么一秒内它总共执行的次数就少于60次;如果你给定的函数执行很快,一秒内总执行次数也不会多于60。
相关文章推荐
- 关于ListView 中有head的时候,有事件要处理的时候,
- 窗体在载入与离开时候的事件处理
- jquery技巧总结-jQuery对象,集合,方法扩展,事件处理,特效,解决冲突
- 【jQuery】on注册事件的时候处理函数自动运行
- matlab 中的数据维数过大的时候怎么处理及技巧
- iPhone开发 当输入的键盘会挡住UITextField的处理事件,当键盘消失的时候界面还原
- jquery技巧总结-jQuery对象,集合,方法扩展,事件处理,特效,解决冲突
- (4)事件处理——(2)在页面加载的时候执行任务(Performing tasks on page load)
- 图像处理之特殊灰度算法技巧
- (一一二)图文混排中特殊文字的点击与事件处理
- eXT 特殊处理UTF-8 到gbk TREE 点击事件
- 有很多类似控件的时候点击事件的处理
- ExtJs 的Enter特殊键事件处理
- (4)事件处理——(2)在页面加载的时候执行任务(Performing tasks on page load)
- 图像处理之特殊灰度算法技巧
- (一一二)图文混排中特殊文字的点击与事件处理
- jquery技巧总结-jQuery对象,集合,方法扩展,事件处理,特效,解决冲突
- matlab 中的数据维数过大的时候怎么处理及技巧
- 常用技巧 之 离开页面事件处理
- 图像处理------特殊灰度算法技巧 分类: 视频图像处理 2015-07-24 09:53 28人阅读 评论(0) 收藏