JS中的函數(shù)節(jié)流(throttle)
一、什么是函數(shù)節(jié)流(throttle)
概念:限制一個(gè)函數(shù)在一定時(shí)間內(nèi)只能執(zhí)行一次。
舉個(gè)栗子:坐火車或地鐵,過(guò)安檢的時(shí)候,在一定時(shí)間(例如10秒)內(nèi),只允許一個(gè)乘客通過(guò)安檢入口,以配合安檢人員完成安檢工作。上例中,每10秒內(nèi),僅允許一位乘客通過(guò),分析可知,“函數(shù)節(jié)流” 的要點(diǎn)在于,在一定時(shí)間之內(nèi),限制一個(gè)動(dòng)作只能執(zhí)行一次。
二、為什么需要函數(shù)節(jié)流
前端開(kāi)發(fā)過(guò)程中,有一些事件或者函數(shù),會(huì)被頻繁地觸發(fā)(短時(shí)間按內(nèi)多次觸發(fā)),最常見(jiàn)的例如,onresize,scroll,mousemove ,mousehover 等,這些事件的觸發(fā)頻率很高,不做限制的話,有可能一秒之內(nèi)執(zhí)行幾十次、幾百次,如果在這些函數(shù)內(nèi)部執(zhí)行了其他函數(shù),尤其是執(zhí)行了操作 DOM 的函數(shù)(瀏覽器操作 DOM 是很耗費(fèi)性能的),那不僅會(huì)造成計(jì)算機(jī)資源的浪費(fèi),還會(huì)降低程序運(yùn)行速度,甚至造成瀏覽器卡死、崩潰。這種問(wèn)題顯然是致命的。
除此之外,重復(fù)的 ajax 調(diào)用不僅可能會(huì)造成請(qǐng)求數(shù)據(jù)的混亂,還會(huì)造成網(wǎng)絡(luò)擁塞,占用服務(wù)器帶寬,增加服務(wù)器壓力,顯然這個(gè)問(wèn)題也是需要解決的。
三、函數(shù)節(jié)流如何解決上述問(wèn)題
根據(jù)上面對(duì)問(wèn)題的分析,細(xì)細(xì)思索,問(wèn)題的解決方案就呼之欲出啦。
主要實(shí)現(xiàn)思路就是通過(guò) setTimeout 定時(shí)器,通過(guò)設(shè)置延時(shí)時(shí)間,在第一次調(diào)用時(shí),創(chuàng)建定時(shí)器,先設(shè)定一個(gè)變量 true, 寫(xiě)入需要執(zhí)行的函數(shù),第二次執(zhí)行這個(gè)函數(shù)時(shí),會(huì)判斷變量是否 true,是則返回。當(dāng)?shù)谝淮蔚亩〞r(shí)器執(zhí)行完函數(shù)最后會(huì)設(shè)定變量為 false。那么下次判斷變量時(shí)則為 false, 函數(shù)會(huì)依次執(zhí)行。目的在于在一定的時(shí)間內(nèi),保證多次函數(shù)的請(qǐng)求只執(zhí)行最后一次調(diào)用。
四、函數(shù)節(jié)流的代碼實(shí)現(xiàn)
根據(jù)以上分析,我們對(duì)“函數(shù)節(jié)流”進(jìn)行代碼實(shí)現(xiàn),如下:
(1) 方法一:時(shí)間戳方案
// 時(shí)間戳方案
function throttle(fn, wait) {
let pre = Date.now()
return function () {
let _this = this
let _arguments = arguments
let now = Date.now()
if (now - pre >= wait) {
fn.apply(_this, _arguments)
pre = Date.now()
}
}
}
function handle() {
console.log(Math.random())
}
window.addEventListener('mousemove', throttle(handle, 1000))
(2) 方法二:定時(shí)器方案
// 定時(shí)器方案
function throttle(fn, wait) {
let timer= null
return function () {
let _this = this
let _arguments = arguments
if (!timer) {
timer = setTimeout(function () {
fn.apply(_this, _arguments)
timer = null
}, wait)
}
}
}
function handle() {
console.log(Math.random())
}
window.addEventListener('mousemove', throttle(handle, 1000))
以上兩種方法本人都親自測(cè)試過(guò),小伙伴們可以放心食用(注意,例子中函數(shù)觸發(fā)方式為 mousemove, 鼠標(biāo)在頁(yè)面上移動(dòng),觀察瀏覽器控制臺(tái)的變化),自己運(yùn)行代碼體驗(yàn)后,自然會(huì)更深刻的理解“函數(shù)節(jié)流”。
五、函數(shù)節(jié)流的使用場(chǎng)景
到此為止,相信各位應(yīng)該對(duì)函數(shù)節(jié)流有了一個(gè)比較詳細(xì)的了解,那函數(shù)節(jié)流一般用在什么情況之下呢?
- 懶加載、滾動(dòng)加載、加載更多或監(jiān)聽(tīng)滾動(dòng)條位置;
- 百度搜索框,搜索聯(lián)想功能;
- 防止高頻點(diǎn)擊提交,防止表單重復(fù)提交
目前遇到過(guò)的使用場(chǎng)景就是這些了,不過(guò)理解了原理,小伙伴可以把它用在需要用到它的任何場(chǎng)合,提高代碼質(zhì)量。
參考鏈接:https://segmentfault.com/a/1190000019577510,版權(quán)歸原作者所有。