为了账号安全,请及时绑定邮箱和手机立即绑定

面试之函数节流和函数防抖

标签:
Vue.js

从场景说起


webp

image.png


滑动到底部继续加载,是移动端很常见的一种场景。

通常来说,我们会在对可滑动区域(一般是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.jianshu.com/p/ad71ab992362


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
205
获赞与收藏
1007

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消