需求
在日常的前端开发中,一般会遇到一些会被频繁触发的事件,比如:window.resize,window.scroll,mousedown,mousemove,keydown,keyup,或者输入框等。这些函数或者是事件一般会被非常频繁的触发。
方案
为了解决这个问题一般会有两种解决方案:防抖(debounce)和节流(throttle)
防抖
原理:假定时间间隔是n秒。那么就是在函数第一次被调用时延时n秒后执行。在这n秒期间之内,再次触发,则以新的事件为准
第一版实现
function deBounce(func, wait) {var timeFlag;return function () {clearInterval(timeFlag);timeFlag = setTimeout(func, wait)}}
第二版实现
第一版实现中会存在this指向不正确的问题
function deBounce(func, wait) {var timeFlag;return function () {var context = this;clearInterval(timeFlag);timeFlag = setTimeout(function () {func.apply(context)}, wait)}}或者使用bindfunction deBounce(func, wait) {var timeFlag;return function () {clearInterval(timeFlag);timeFlag = setTimeout(func.bind(this), wait)}}
第三版实现
第二版中的实现存在传参的问题
function deBounce(func, wait) {var timeFlag;return function () {var context = this;var args = argumentsclearInterval(timeFlag);timeFlag = setTimeout(function () {func.apply(context, args)}, wait)}}或者bindfunction deBounce(func, wait) {var timeFlag;return function (...args) {clearInterval(timeFlag);timeFlag = setTimeout(func.bind(this, ...args), wait)}}或者es6const deBounce = (func, wait) => {let timeFlag;return function (...args) {clearInterval(timeFlag);timeFlag = setTimeout(func.bind(this, ...args), wait)}};
第四版实现
有时会有需要立即执行的需求。
function deBounce(func, wait, immediate) {var timeFlag;return function () {var context = this;var args = arguments;timeFlag && clearInterval(timeFlag);if (immediate) {var callNow = !timeFlag;timeFlag = setTimeout(function () {timeFlag = null}, wait);if (callNow) func.apply(context, args)} else {timeFlag = setTimeout(function () {func.apply(context, args)}, wait)}}}// 或者const deBounce = (func, wait, immediate) => {let timeFlag;return function (...args) {clearInterval(timeFlag);if (immediate) {const oldFlag = !timeFlag;timeFlag = setTimeout(() => {timeFlag = null}, wait);oldFlag && func.apply(this, args)} else {timeFlag = setTimeout(func.bind(this, ...args), wait)}}};
第五版
第四版的函数仍然存在部分问题。就是当函数立即执行时。可能需要函数的返回值,所以修改后有下面第五版
function deBounce(func, wait, immediate) {var timeFlag;var deBounced = function () {var context = this;var args = arguments;var result;timeFlag && clearInterval(timeFlag);if (immediate) {var callNow = !timeFlag;timeFlag = setTimeout(function () {timeFlag = null}, wait);if (callNow) result = func.apply(context, args)} else {timeFlag = setTimeout(function () {func.apply(context, args)}, wait)}return result};deBounced.cancel = function () {clearTimeout(timeout);timeout = null;};return deBounced;}// es6const deBounce = (func, wait, immediate) => {let timeFlag;const deBounced = (...args) => {clearInterval(timeFlag);if (immediate) {const oldFlag = !timeFlag;timeFlag = setTimeout(() => {timeFlag = null}, wait);oldFlag && func.apply(this, args)} else {timeFlag = setTimeout(func.bind(this, ...args), wait)}};deBounced.cancel = () => {clearTimeout(timeFlag);timeFlag = null;};return deBounced};
