问题由来:
在项目应用PeoplePicker控件的时候突然联想到一个问题,在输入人名时不停的向后台发请求,取到数据库里面的数据。我们都知道频繁的通信会导致页面效率降低。可不可以设置个间隔,每次这个间隔通信一次而不是每次输入一个字符就通信一次呢。其实这里还有很多场景,比如resize事件,scroll事件。都会让一个回调函数不停的执行。页面操作成本是非常高的,如果不停的执行页面效率会打打折损。于是产生了两种解决方案:函数节流、函数去抖。
函数节流:
频繁的调用一个函数,我们可以添加一些限制,可以缓解频繁调用,我们可以设置个时间间隔,每次到时间调用一次。
代码:
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> </head> <body> <input id="search" type="text" name="search"> <script> function queryData(text) { console.log(text); } var input = document.getElementById("search"); var handler = throttle(queryData, 1000); input.addEventListener("keyup", function (event) { handler(this.value); }); function throttle(fn, delay) { var self = this, lastTime = 0, timer; return function (value) { var now = new Date().getTime(); if (now - lastTime <= delay) { return; } lastTime = now; clearTimeout(timer); timer = setTimeout(function () { timeout = null; fn.apply(self, [value]); }, delay) } } </script> </body> </html>
思路:利用闭包函数throttle保存timer以及lastTime,如果两次的调用时间间隔小于设置的规定时间,就不去调用目标函数,如果大于这个时间间隔,就去设置一个timer,然后执行这个函数。这样做的目的可以达到频繁调用函数,但是需要在一段时间才回去执行该函数,这种方式就叫做函数节流。
效果:
一直不停的输入,没1秒会打一次log。
函数去抖:
去抖可以理解成为是节流的一种情况,在一个条件内函数一直不执行,直到调出该条件。
代码:
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> </head> <body> <input id="search" type="text" name="search"> <script> function queryData(text) { console.log(text); } var input = document.getElementById("search"); var handler = debounce(queryData, 5000); input.addEventListener("keyup", function (event) { handler(this.value); }); function debounce(fn, delay) { var timer, self = this; return function (value) { clearTimeout(timer); timer = setTimeout(function () { timer = null; fn.apply(self, [value]); }, delay); }; } </script> </body> </html>
思路:函数调用n秒后才会执行,如果函数在n秒内被调用的话,则函数不执行,重新计算执行时间。
效果:
不停的输入不会打出log,停止输入打出log。
总结:函数节流在一定程度上可以优化页面效率,减少没必要的dom渲染以及http请求,更重要的是对js可以有一个更深入的理解。