JavaScript 函数防抖和函数节流.

JavaScript 函数防抖和函数节流.

在浏览器执行环境中,等待主队列任务(DOM TREE & CSS Tree & render Tree) 等任务执行完毕之后.

就开始执行 EventLoop 环境事件了.

所以,某种程度上,浏览器是基于事件驱动的

既然提到了事件,那么我们最常见的就是给一些元素绑定一些事件了.

比如给一个按钮绑定一个click事件.


给元素绑定一个事件

给元素绑定一个事件,是一个非常常见的场景.

btn.onclick = function (e) {
    console.log('xxxxx')
}

这没什么大不了的.


函数节流

先不要管什么是函数节流.

上述我们给一个按钮添加了一个点击事件.

每次点击这个按钮的时候,都会触发这个事件响应函数.

这个是没毛病的.

之前也都是这么做的.

但是如果,一个哥们单身30年,手速很快

假如这个哥们一秒能点击100下. 且这又是一个发送ajax请求的按钮.

那么,每一秒钟

  • 前端浏览器,这个按钮的事件响应函数执行了100次.发送了100个请求.
  • 后台服务器每一秒接受到了100个请求.并处理这100个请求.

现在有一个需求是,这个按钮一秒钟不管点击多少下,只能执行一下.(你手速在快也没有用)

这个需求描述的就是函数节流.

某些函数可能会出现非常频繁的调用,但是在某一个周期内,不管触发多少次,实际上只能被执行一次.

所以需要这么一个机制:

  • 一个函数被执行了.(此时计时是A)
  • 这个函数又被执行了.(此时计时是B)
  • 如果(B-A<等待值),那么这个函数就不执行.
  • 否则就执行.
<h4>节流</h4>
<p>节流就是指函数大于等于某个时间周期才能执行.否则就不执行.一个周期范围内只能处理一次.</p>
<div id="show">0</div>
<button id='jl'>函数节流</button>
  let canClick = true
  let counter = 0
  document.getElementById('jl').addEventListener('click', function () {
    if (canClick) {
      canClick = false
      console.log(++counter)
      setTimeout(() => {
        canClick = true
      }, 1000);
    }
  }, false)

利用一个 canClick 变量来标记这个按钮是否被点击.

并在一个 setTimeout 的定时器里,定时1秒去修改这个 canClick

于是,目的就达到了..每次点击之后,下一次点击有效必须要等待一秒.

但这样的做法,不具备通用性.

可以封装一个函数节流的方法,把需要节流的函数通过这个方法封装.

function throttle (handler, wait) {
    let lastTime = 0
    return function () {
        let nowTime = new Date().getTime()
        if (nowTime - lastTime > wait) {
            hanlder.apply(this,arguments)
            lastTime = nowTime
        }
    }
}
 function hanlder (e) {
    e.stopPropagation()
    show.innerText = parseInt(show.innerText) + 1
}

jl.addEventListener('click', throttle(hanlder, 1000), false)

函数节流:

  • 这个函数可能存在频繁执行的情况(手速飞快,点击按钮)
  • 我们希望这个函数在某个周期内只执行一次.

函数防抖

其实和函数节流一样.

函数防抖也是用于解决某些函数频繁触发的情况.

但不同的是:

  • 函数节流,指的是在某一个周期内,只能执行一次此函数
  • 函数防抖,指的是必须超过某一个时间阈值,否则函数不执行.

一个比较常见的场景.

在文本框内输入搜索字符,并实时的发送搜索关键字到后台.

正常情况下,一般都是这么写的.

<input type="text" name="" id="inp">
 inp.addEventListener('input', function () {
    console.log(this.value)
  }, false)
image.png

发现每次输入一个文本都会触发一次input事件响应函数.

此函数的触发频率完全取决于用户在输入框中,输入的文本快慢.

这没有什么问题,input 事件就是这么定义的.

但是对于实际场景而言,可能就出现了如下的不足:

  • 每次文本变动,都会触发 input 从而触发后台的请求操作.
  • 对于用于而言,可能需要查询的是 123321 字符串. 而文本的输入会导致之前的5次查询都是无效的.

所以,这里就需要就一个机制..

  • 事件函数不是立马执行.
  • 会等待一段时间
  • 如果在等待的这一段事件内,事件函数又被触发了.
  • 那么上一次的事件函数就不会执行.
  • 接着等待一段时间.
  • 如此循环
  • 直到等待时间超过了,且用户没有操作了.我在执行这个事件函数.

这个就是所谓的函数节流.

除非函数不触发了,且超过某个时间阈值,否则之前的事件都不会触发.

代码改写为:

 let inp = document.getElementById('inp')
  let timer = null
  inp.addEventListener('input', function () {
    clearTimeout(timer)
    timer = setTimeout(() => {
      console.log(this.value)  
    }, 1000);
    
  }, false)

结果:

image.png

只有等待用户操作停止了,并达到某一个等待的时间阈值,再最后触发事件响应函数.

上述的代码不具备通用性.

封装函数节流方法 debounce

function debounce (hanlder, wait) {
    let timer = null
    return function () {
        clearTimeout(timer)
        timer = setTimeout(() => {
            hanlder.apply(this,arguments)
        }, wait)
    }
}

所以整体代码可以改写为

 function inputHanlder(e) {
    console.log(this.value, e)
  }
  // 函数防抖 , 频繁
  function debounce(hanlder, wait) {
    let timer = null
    return function () {
      clearTimeout(timer)
      timer = setTimeout(() => {
        hanlder.apply(this, arguments)
      }, wait);
    }
  }

  inp.addEventListener('input',debounce(inputHanlder,1000), false)

总结

  • 不管是函数防抖还是函数节流,都是为了解决函数频繁执行的问题.
  • 函数防抖:函数在单位时间内,只会被触发一次.
  • 函数节流:函数只有在超过了某个时间阈值后才会被执行.否则函数不执行.

一个只执行一次(函数节流).

一个不满足条件就一次也不执行(函数防抖).

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,219评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,363评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,933评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,020评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,400评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,640评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,896评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,597评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,327评论 1 244
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,581评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,072评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,399评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,054评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,849评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,672评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,585评论 2 270

推荐阅读更多精彩内容

  • 函数节流 还记得上篇文章中说到的图片懒加载吗?我们在文章的最后实现了一个页面滚动时按需加载图片的方式,即在触发滚动...
    柏丘君阅读 2,787评论 1 19
  • 在日常开发中,我们经常能够碰到以下工作场景: 对提交按钮进行变态的点击压力测试输入框内容的实时校验(譬如验证用户名...
    叫我小徐阅读 968评论 0 5
  • 前言 最近和前端的小伙伴们,在讨论面试题的时候。谈到了函数防抖和函数节流的应用场景和原理。于是,想深入研究一下两者...
    youthcity阅读 23,363评论 5 77
  • 我觉得我偶尔孩子气很重,我想了想,这是好事,跟舒服的人相处才会有的样子,我一直想把这种状态拾回来
    茶花雨阅读 165评论 0 0
  • 综艺类: 王牌对王牌:我也是前几天的时候看到的,室友推荐我去看的,真的是超搞笑,我现在在看第四季,每一期都很好,有...
    梁家_大少爷阅读 206评论 0 1