我們用兩張圖表示什么是節流和防抖。


由圖可見,防抖的意思是,當用戶在一段時間內連續頻繁的試圖執行一個函數的時候,只有最后一次,函數被真正的執行。節流的意思是,當用戶在某一個時刻執行了一次函數的時候,在一段時間 t 內,再次執行該函數都沒有作用。
下面,我們用實例,寫一個防抖和節流出來。
請先利用下面的命令安裝 jquery,在項目根目錄下執行。
npm install jquery -save
在 body 里添加
<button id="btn1">btn1</button>
一、防抖
let id;$("#btn1").on('click',function(e){clearTimeout(id);id = setTimeout(function(){console.log('button clicked',id)},1000);})
這是一個最簡單的防抖,但是,缺點是明顯的,一個臨時變量被放在 window 對象里面了,污染了全局變量空間。因此,我們想把這個變量寫成局部的,有經驗的同學一定知道,我們該用閉包了,既,使用柯理化函數的編程思想。事實上,上面的這個例子已經是一個閉包了,因為最外層的 id 接住了函數內部 setTimeout 的返回值,因此這個函數的棧內存是不會銷毀的。只是,我們的優化方案需要在此基礎上再加一層。
本著這個思路,我們有:
function debounce(){let id;return function(){clearTimeout(id);id = setTimeout(function(){console.log('button clicked',id)},1000);}}var fn = debounce();$("#btn1").on('click',function(e){fn();})
首先,一個全局變量 fn 接住了 debounce 的一個返回值,閉包形成,debounce 內部的 id 被保存住,因此,每次 fn 執行的時候,它所用到的 id 都是一個,這和第一個例子當中全局作用域上面的 id 是等價的,只不過,不會污染全局作用域。
防抖的原理是,如果用戶頻繁的點擊按鈕,上一次的 setTimeout 都會立刻被下一次清除,需要執行的函數始終打不出來,只有最后一次沒人清除它,因此會被執行。
二、節流
下面我們講節流,首先,我們還是利用全局作用域寫一個簡單的版本。
let time = new Date();$("#btn1").on('click', function (e) {let time1 = new Date();if (time1 - time > 2000) {console.log(time1 - time);time = time1;}})
同樣的,這套方法污染了全局作用域,因此,我們需要寫個閉包出來,保存局部變量。
function throttle() {let time = new Date();return function () {let time1 = new Date();if (time1 - time > 2000) {console.log(time1 - time);time = time1;}}}let fn = throttle();$("#btn1").on('click', function (e) {fn();})
節流的原理比防抖更簡單,當函數被成功的執行過一次,本次成功執行的時間會被記錄下來,那么當用戶頻繁點擊按鈕的時候,這些次記錄的時間距離上次成功執行的時間太短,小于閾值,因此不被執行。
請各位同學一定要把代碼搞到本地跑一遍,這樣才能加深印象。