前端优化 —— 函数的节流和防抖

参考https://www.pandashen.com/2017/06/12/20170612130942/

前言

在前端开发当中我们经常会绑定一些事件触发的某些程序执行,有时这些事件会连续触发,如浏览器窗口 scroll、resize,输入框的 keyup、input,以及 click 事件在连续点击时连续发送请求等等,这些情况有些会严重影响前端性能,有些会增加服务器压力,使用户体验大打折扣,而函数节流和防抖就是为了解决这样的问题。

函数节流 throtter

函数节流:当持续发生事件时,保证在一个固定的时间间隔只执行一次真正的事件处理程序,通俗的说就像 “节流” 的名字一样,打开水龙头时要秉承勤俭节约的原则,把阀门关小,最好是达到在固定间隔内水一滴一滴的往下流。

节流函数的时序图

fun-throtter.png

从图中可以看出,连续触发事件时,真正执行事件处理程序的间隔是固定的,多次触发,也只会在某一个时间间隔内触发一次,由于事件处理函数内部执行逻辑各不相同,我们就封装一版可通用的节流函数。

节流函数的封装

文件:throtter.js

// 节流函数
const throtter = (func, delay = 60) => {
    // 锁的标识
    let lock = false;

    // 返回一个事件处理函数
    return (...args) => {
        // 如果 lock 为 true 则跳出
        if (lock) return;

        // 执行函数并更改锁的状态
        func(...args);
        lock = true;

        // 添加定时器,在到达时间间隔时重置锁的状态
        setTimeout(() => lock = false, delay);
    }
}

throtter 函数有两个参数,第一个参数为在事件触发时真正要执行的函数,第二个参数为定义的间隔时间,在函数执行时定义了 lock 的初始值,通过闭包返回一个函数作为事件处理函数,在返回的函数内部判断 lock 状态并确定执行真正的函数 func 还是跳出,每次执行 func 后会更改 lock 状态,通过定时器在规定的时间间隔内重置 lock,这就是函数节流的原理。

验证节流函数

文件:throtter-test.js

// 使用节流函数
document.addEventListener("scroll", throtter(console.log));

上面我们给 document 对象添加了滚动事件,并不断的打印事件对象,事件处理函数的默认参数为事件对象,从执行效果应该可以看出,平均每 60ms 才会触发一次事件,达到了优化性能的目的,如果想让真正执行的函数 func 传入更多的参数,只需如下处理。
文件:throtter-test.js

// a b 为函数要传入的参数
let a = 1, b = 2;

// 返回事件处理函数
const func = throtter(console.log);

// 添加事件监听
document.addEventListener("scroll", e => func(e, a, b));

节流函数一般用于 scroll、resize 事件的情况较多,因为这些事件的触发是连续性的,需要在一个时间间隔内只触发一次。

函数防抖 debounce

函数防抖:当持续发生事件时,事件只在上一次触发后的一段时间内没再触发事件,才会真正的执行事件处理逻辑,如果每两次触发的间隔小于这个时间,则不执行事件逻辑。

防抖函数的时序图

fun-debounce.png

从图中可以看出,连续触发事件时并没有执行事件处理函数,只有在某一阶段连续触发后的最后一次才执行,也就是上一次触发的时间间隔要大于设定值才执行,同样的,事件处理函数内部执行逻辑各不相同,我们就封装一版可通用的防抖函数。

防抖函数的封装

文件:debounce.js

// 防抖函数
const dobounce = (func, delay = 300, timer = null) => {
    return (...args) => {
        // 清除定时器
        clearInterval(timer);

        // 在定时器到时后执行事件处理函数
        timer = setTimeout(() => func(...args), delay);
    }
}

dobounce 函数有三个参数,第一个参数为在事件触发时真正要执行的函数,第二个参数为执行事件的延迟时间,第三个参数为定时器 ID 的初始值,执行 dobounce 通过闭包返回了事件处理函数,在处理函数内部先清除定时器,然后定义定时器并将 ID 赋值给 timer,如果事件连续触发,则会不断的清除定时器,直到有一次触发间隔超过了设定延时时间 delay,才会真正执行 func。

验证防抖函数

文件:index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>函数防抖</title>
</head>
<body>
    <input type="text" id="ipt">
</body>
</html>

文件:debounce-test.js

// 使用防抖函数
let ipt = document.querySelector("#ipt");

// 添加事件监听
ipt.addEventListener("keyup", debounce(console.log));

上面的功能跟 throtter 类似,真正执行事件处理函数时打印事件对象,通过验证,连续输入触发 keyup 事件,上一次触发和下一次触发间隔时间必须大于 300ms 才会执行打印事件对象的逻辑,如果想传入多个参数套路相同。

文件:debounce-test.js

// 获取 dom 元素
let ipt = document.querySelector("#ipt");

// a b 为函数要传入的参数
let a = 1, b = 2;

// 返回事件处理函数
const func = debounce(console.log);

// 添加事件监听
ipt.addEventListener("keyup", e => func(e, a, b));

防抖函数一般用于输入框事件,常用场景就是搜索或查询,如果不使用防抖会连续发送请求,增加服务器的压力,使用防抖后,会在用户输入要查询的关键词后才发送请求,这也更符合用户的习惯,例如百度搜索,就是这样实现的。

总结

“节流” 和 “防抖” 是前端在项目中经常使用的优化手段,代码虽然不多,但是确是前端面试 “出镜率” 非常高的知识点,从而能看出它们的重要性,所以建议前端同学们一定要知道,并能手写,这是 “一箭双雕” 的事,可以用来通过面试,也可以因为工作中遇到直接就写而提高工作效率。

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

推荐阅读更多精彩内容