函数节流和函数防抖

从场景说起 滑动到底部继续加载,是移动端很常见的一种场景。 通常来说,我们会在对可滑动区域(一般是window)的scroll事件做监听,判断距离底部还有多远,如果距离底部较近,则发起HTTP请求,请求下一页的数据。 很容易写出这样的代码: let page = 0; document.querySelector('.main').addEventListener('scroll', () => { scrollMore(this); }) // 滑动获取更多内容 function scrollMore(el) { if (getScrollTop(el) + getClientHeight() >= getScrollHeight(el) - 100) { fetch('http://api.jd.com/somethings/' + page++) .then(function(response) { console.log(response.json()); // do something 把数据填充到页面上 }) } } function getScrollTop(el) { //取窗口滚动条高度 return el.scrollTop; } function getClientHeight() { //取窗口可视范围的高度 let clientHeight = 0; if (document.body.clientHeight && document.documentElement.clientHeight) { clientHeight = (document.body.clientHeight < document.documentElement.clientHeight) ? document.body.clientHeight : document.documentElement.clientHeight; } else { clientHeight = (document.body.clientHeight > document.documentElement.clientHeight) ? document.body.clientHeight : document.documentElement.clientHeight; } return clientHeight; } function getScrollHeight(el) { //取文档内容实际高度 return Math.max(document.body.scrollHeight, el.scrollHeight); } 但是这样很容易就发现一个问题,触发的scroll事件太频繁了,在一些低端机上,可能会卡顿。 其实我们的判断没有必要这么频繁,用户的滑动操作是一段时间内不停触发的。 我们希望在一小段时间内,只触发一次执行。 函数节流 这就是函数节流要做的事情,《JavaScript高级程序设计》中给了一个方法: function throttle (method, context) { clearTimeout(method.tId); method.tId = setTimeout(function () { method.call(context); }, 100) } 这个代码的原理就是在多次执行的时候,清除上一次的timeout,如果时间间隔没有超过100ms,则又新建一个新的timeout,旧的则被丢弃。 考虑一下,如果在一段时间内,每隔99ms触发一次,那么不停地清除上一次的timeout,函数将永远不会执行。 我们更希望,每隔100ms,函数就执行一次,而不是像现在一样。 重新思考这个问题。 关键点有两个: 间隔 执行 先来把函数封装一下,将节流函数return出来: function throttle1 (method, delay) { let timer = null; return function () { let context = this ; if (timer) clearTimeout(timer); timer = setTimeout(() => { method.call(context); }, delay) } } 加上间隔判定: function throttle2 (method, delay) { let timer = null; let start; return function () { let context = this , current = Date.now() ; if (timer) clearTimeout(timer); if (!start) { start = current; } if (current - start >= delay) { method.call(context); start = current; } else { timer = setTimeout(() => { method.call(context); }, delay) } } } 这样,基本上完成了一个throttle函数。 函数防抖 防抖的场景也比较常见。 比如搜索时,监听用户输入,提供联想词;或者用户连续点击提交按钮的场景。 说实话,我感觉《高级》那本书里的节流例子,就是一个防抖的版本。 几乎可以拿来就用。 我们还是做一个比较完善的版本。 function debounce (method, delay) { let timeout = null; return function () { clearTimeout(timeout); timeout = setTimeout(() => { method.apply(this, arguments); }, delay); }; }从场景说起 滑动到底部继续加载,是移动端很常见的一种场景。 通常来说,我们会在对可滑动区域(一般是window)的scroll事件做监听,判断距离底部还有多远,如果距离底部较近,则发起HTTP请求,请求下一页的数据。 很容易写出这样的代码: let page = 0; document.querySelector('.main').addEventListener('scroll', () => { scrollMore(this); }) // 滑动获取更多内容 function scrollMore(el) { if (getScrollTop(el) + getClientHeight() >= getScrollHeight(el) - 100) { fetch('http://api.jd.com/somethings/' + page++) .then(function(response) { console.log(response.json()); // do something 把数据填充到页面上 }) } } function getScrollTop(el) { //取窗口滚动条高度 return el.scrollTop; } function getClientHeight() { //取窗口可视范围的高度 let clientHeight = 0; if (document.body.clientHeight && document.documentElement.clientHeight) { clientHeight = (document.body.clientHeight < document.documentElement.clientHeight) ? document.body.clientHeight : document.documentElement.clientHeight; } else { clientHeight = (document.body.clientHeight > document.documentElement.clientHeight) ? document.body.clientHeight : document.documentElement.clientHeight; } return clientHeight; } function getScrollHeight(el) { //取文档内容实际高度 return Math.max(document.body.scrollHeight, el.scrollHeight); } 但是这样很容易就发现一个问题,触发的scroll事件太频繁了,在一些低端机上,可能会卡顿。 其实我们的判断没有必要这么频繁,用户的滑动操作是一段时间内不停触发的。 我们希望在一小段时间内,只触发一次执行。 函数节流 这就是函数节流要做的事情,《JavaScript高级程序设计》中给了一个方法: function throttle (method, context) { clearTimeout(method.tId); method.tId = setTimeout(function () { method.call(context); }, 100) } 这个代码的原理就是在多次执行的时候,清除上一次的timeout,如果时间间隔没有超过100ms,则又新建一个新的timeout,旧的则被丢弃。 考虑一下,如果在一段时间内,每隔99ms触发一次,那么不停地清除上一次的timeout,函数将永远不会执行。 我们更希望,每隔100ms,函数就执行一次,而不是像现在一样。 重新思考这个问题。 关键点有两个: 间隔 执行 先来把函数封装一下,将节流函数return出来: function throttle1 (method, delay) { let timer = null; return function () { let context = this ; if (timer) clearTimeout(timer); timer = setTimeout(() => { method.call(context); }, delay) } } 加上间隔判定: function throttle2 (method, delay) { let timer = null; let start; return function () { let context = this , current = Date.now() ; if (timer) clearTimeout(timer); if (!start) { start = current; } if (current - start >= delay) { method.call(context); start = current; } else { timer = setTimeout(() => { method.call(context); }, delay) } } } 这样,基本上完成了一个throttle函数。 函数防抖 防抖的场景也比较常见。 比如搜索时,监听用户输入,提供联想词;或者用户连续点击提交按钮的场景。 说实话,我感觉《高级》那本书里的节流例子,就是一个防抖的版本。 几乎可以拿来就用。 我们还是做一个比较完善的版本。 function debounce (method, delay) { let timeout = null; return function () { clearTimeout(timeout); timeout = setTimeout(() => { method.apply(this, arguments); }, delay); }; }https://www.cnblogs.com/liuyongjia/p/9457199.html
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信