js 高程 函数节流 throttle() 分析与优化
在 js 高程 22.3.3章节 里看到了 函数节流 的概念,觉得给出的代码可以优化,并且概念理解可以清晰些,所以总结如下:
先看 函数节流 的定义,书上原话(斜体表示):
产生原因/适用场景:
浏览器中某些计算和处理要比其他的昂贵很多。例如,DOM 操作比起非 DOM 交互需要更多的内存和 CPU 时间。连续尝试进行过多的 DOM 相关操作可能会导致浏览器挂起,有时候甚至会崩溃。尤其在 IE 中使用onresize 事件处理程序的时候容易发生,当调整浏览器大小的时候,该事件会连续触发。
在onresize 事件处理程序内部如果尝试进行 DOM 操作,其高频率的更改可能会让浏览器崩溃。为了绕开这个问题,你可以使用定时器对该函数进行节流。
基本思想:
函数节流背后的基本思想是指,某些代码不可以在没有间断的情况连续重复执行。第一次调用函数,创建一个定时器,在指定的时间间隔之后运行代码。当第二次调用该函数时,它会清除前一次的定时器并设置另一个。如果前一个定时器已经执行过了,这个操作就没有任何意义。然而,如果前一个定时器尚未执行,其实就是将其替换为一个新的定时器。目的是只有在执行函数的请求停止了一段时间之后才执行。
我的理解:
譬如 onresize 和 onmouseover 事件,在 缩放浏览器 和 鼠标滑过 时,是不间断触发的,仅仅是 缩放下浏览器 和 滑过鼠标 这个看似简单的动作,其实已经触发了 n 次 onresize 和 onmouseover 事件了,如果绑定的事件处理程序又有点复杂,那这个 n 次执行时很耗资源的;
举例:
function mouseoverConsole() {
console.log('mousemove');
}
document.onmouseover = mouseoverConsole;
这个代码很简单,如果我们鼠标滑过下文档,你会发现:
仅仅是滑下,这个 mouseoverConsole 就执行了 13次,如果用户滑过的次数多些,时间久些,那么这个 mouseoverConsole 就会执行更多次,如果这个函数本身不耗资源也就算了,如果很耗资源呢,那就可能造成页面卡顿;
再举个例子,onresize 事件,可能会造成浏览器重新计算布局,如果布局很复杂,在缩放浏览器的时候,onresize 事件又在不断触发,就可能造成浏览器卡顿,虽然用户缩放浏览器可能只用了1s不到,但是触发了 onresize 事件可能有20次,然而 onrsize 触发的第一次事件处理程序可能还没执行完,而后面还有 19 次需要执行,自然就会卡顿;
那么如果说,第一次的还在执行或还没执行,在 100ms 内又触发了 9 次,那么实际上,直接执行第 10 次的事件处理程序就可以了,因为,100ms 内页面调整 10 次 和调整 1 次,用户是区分不出来的,但是运行 10 次 和 1 次对于浏览器而言所耗资源是不一样的,尤其是事件处理程序复杂时;这就是我理解的 函数节流 的思想;
函数节流优点:
节省资源,案例见上例子;
函数节流缺点:
效果延时,动态效果受影响,不过可以通过缩短间隔时间来优化解决,比如 100ms 改成 10ms;
譬如,极端点,如果用户一直在不停滑鼠标,中间 100ms 都没有停过,那么根据函数节流的思想,绑定的事件处理程序就一直不会执行,直到,用户停下来有 100ms 的时间才会开始执行绑定的事件处理程序;就像你缩放浏览器一直没停,那么页面就会在你停下来的时候才会调整,自然你就看不到中间缩放时页面的变化;
因为第 2 次触发会把第一次的事件处理程序停掉,第 3 次的停第 2 次的,一直到中间停下来 100ms ,那么当次的事件处理程序才会执行;当然如果把 100ms 改成 10ms ,缺点就会降低,当然所占资源就会增加,所以中间的间隔时间提供了一个选择,可以修改间隔时间来平衡性能和效果;
下面来上代码,书上代码,关于 apply() ,arguments 不明白的看 这里:
普通代码,不进行函数节流:
window.onresize = function() {
var div = document.getElementById("myDiv");
div.style.height = div.offsetWidth + "px";
};
函数节流代码:
window.onresize = function() {
throttle(resizeDiv);
}; function throttle(method, context) {
clearTimeout(method.tId);
method.tId = setTimeout(function() {
method.call(context);
}, 100);
} function resizeDiv() {
var div = document.getElementById("myDiv");
div.style.height = div.offsetWidth + "px";
}
这里,调整大小的功能被放入了一个叫做 resizeDiv() 的单独函数中。然后onresize 事件处理程序调用throttle()并传入 resizeDiv 函数,而不是直接调用 resizeDiv()。多数情况下,用户是感觉不到变化的,虽然给浏览器节省的计算可能会非常大。
只要代码是周期性执行的,都应该使用节流,但是你不能控制请求执行的速率。这里展示的 throttle() 函数用了 100ms 作为间隔,你当然可以根据你的需要来修改它。
我自己优化了下,这样调用的时候更简单,可以直接设置 时间间隔(平衡性能和展示),且可以传递 event 对象;
document.onmouseover = throttle(mouseoverConsole,100); function throttle(method,interval,context) {
return function() {
var args = arguments;
clearTimeout(method.timeoutId);
method.timeoutId = setTimeout(function() {
method.apply(context, args);
}, interval);
};
} function mouseoverConsole(event) {
console.log(event.type);
}
最新文章
- Oracle使用SQL传输表空间
- JS+CSS3人物奔跑动画
- Spring boot 学习记录
- TAP/TUN摘要
- java中FileInputStream和FileOutputStream对图片操作的例子
- D3.js 理解 Update、Enter、Exit
- IIS问题汇总
- ajax异步传输
- Nagios监控的部署与配置
- Python中 sys.argv[]的用法简明解释
- DWR使用总结
- [Android] Android 使用 Greendao 操作 db sqlite(1)-- 直接在MainActivity中调用
- GLSL版本的区别和对比
- C#改变图片大小
- AtCoder Regular Contest 094 D Worst Case
- B+树和LSM比较(转)
- UVA 10815:Andy's First Dictionary(STL)
- Idea代码可视化插件
- charles工具过滤腾讯视频播放器广告
- 数据结构与算法之排序(2)选择排序 ——in dart
热门文章
- Atitit.404错误解决标准流程and url汉字中文路径404错误resin4 resin chinese char path 404 err解决
- 线程相关函数(6)-pthread_cond_wait(),pthread_cond_signal(), 条件变量
- python-爬图小样
- :-1: error: [debug/moc_gotocelldialog.cpp] Error 2
- 悦铃文件必须是CCITT A_Law格式的,且没有被压缩
- nodejs具体解释
- 演练:创建和注册自定义 HTTP 模块
- PHP——数组中的each(),list()和while循环遍历数组
- VIM打开shell脚本中文乱码解决
- 29个酷炫的Firefox配置参数