摘要:基礎(chǔ)防抖我們現(xiàn)在寫(xiě)一個(gè)最基礎(chǔ)的防抖處理標(biāo)記事件也做如下改寫(xiě)現(xiàn)在試一下,我們會(huì)發(fā)現(xiàn)只有我們停止?jié)L動(dòng)秒鐘的時(shí)候,控制臺(tái)才會(huì)打印出一行隨機(jī)數(shù)。
為何要防抖和節(jié)流
有時(shí)候會(huì)在項(xiàng)目開(kāi)發(fā)中頻繁地觸發(fā)一些事件,如 resize、 scroll、 keyup、 keydown等,或者諸如輸入框的實(shí)時(shí)搜索功能,我們知道如果事件處理函數(shù)無(wú)限制調(diào)用,會(huì)大大加重瀏覽器的工作量,有可能導(dǎo)致頁(yè)面卡頓影響體驗(yàn);后臺(tái)接口的頻繁調(diào)用,不僅會(huì)影響客戶端體驗(yàn),還會(huì)大大增加服務(wù)器的負(fù)擔(dān)。而如果對(duì)這些調(diào)用函數(shù)增加一個(gè)限制,讓其減少調(diào)用頻率,豈不美哉?
針對(duì)這個(gè)問(wèn)題,一般有兩個(gè)方案:
防抖 (Debounce)
節(jié)流 (Throttle)
我對(duì)函數(shù)防抖的定義:當(dāng)函數(shù)被連續(xù)調(diào)用時(shí),該函數(shù)并不執(zhí)行,只有當(dāng)其全部停止調(diào)用超過(guò)一定時(shí)間后才執(zhí)行1次。
一個(gè)被經(jīng)常提起的例子:
上電梯的時(shí)候,大家陸陸續(xù)續(xù)進(jìn)來(lái),電梯的門(mén)不會(huì)關(guān)上,只有當(dāng)一段時(shí)間都沒(méi)有人上來(lái),電梯才會(huì)關(guān)門(mén)。
Talk is cheap,我們直接 show code 吧。
先做基本的準(zhǔn)備(篇幅原因,HTML部分省略):
let container = document.getElementById("container"); // 事件處理函數(shù) function handle(e) { onsole.log(Math.random()); } // 添加滾動(dòng)事件 container.addEventListener("scroll", handle);
我們發(fā)現(xiàn),每滾動(dòng)一下,控制臺(tái)就會(huì)打印出一行隨機(jī)數(shù)。
基礎(chǔ)防抖我們現(xiàn)在寫(xiě)一個(gè)最基礎(chǔ)的防抖處理:
function debounce(func, wait) { var timeout;//標(biāo)記 return function() { clearTimeout(timeout); timeout = setTimeout(func, wait); } }
事件也做如下改寫(xiě):
container.addEventListener("scroll", debounce(handle, 1000));
現(xiàn)在試一下, 我們會(huì)發(fā)現(xiàn)只有我們停止?jié)L動(dòng)1秒鐘的時(shí)候,控制臺(tái)才會(huì)打印出一行隨機(jī)數(shù)。
標(biāo)準(zhǔn)防抖以上基礎(chǔ)版本會(huì)有兩個(gè)問(wèn)題,請(qǐng)看如下代碼:
// 處理函數(shù) function handle(e) { console.log(this); //輸出Window對(duì)象 console.log(e); //undefined }
沒(méi)錯(cuò),當(dāng)我們不使用防抖處理時(shí),handle()函數(shù)的this指向調(diào)用此函數(shù)的container,而在外層使用防抖處理后,this的指向會(huì)變成Window。
其次,我們也要獲取到事件對(duì)象event。
所以我們要對(duì)防抖函數(shù)做以下改寫(xiě):
function debounce(fn, wait) { let timeout; return function() { clearTimeout(timeout); timeout = setTimeout(()=>{ fn.apply(this,arguments)//使用apply改變this指向 }, wait); } }
當(dāng)然了,如果使用箭頭函數(shù)便可以省去外層聲明。
先觸發(fā)式防抖以上的情況都是只有當(dāng)連續(xù)觸發(fā)停止后才執(zhí)行,那如果我們想讓事件第一次觸發(fā)就執(zhí)行,后面的連續(xù)觸發(fā)都不執(zhí)行,直到停止觸發(fā)一段時(shí)間才可以再次觸發(fā)(比如防止頻繁點(diǎn)擊),該如何處理呢?
那么可以利用同樣的原理,稍作修改即可:
function debounce(fn, wait) { let timeout; return function(){ let arg = arguments; let that = this; clearTimeout(timeout); !timeout && fn.apply(that,arg) timeout = setTimeout(function(){ timeout = null; }, wait); } }節(jié)流 (Throttle)
顧名思義,節(jié)流就是節(jié)約流量,將連續(xù)觸發(fā)的事件稀釋成預(yù)設(shè)評(píng)率。
比如每間隔1秒執(zhí)行一次函數(shù),無(wú)論這期間觸發(fā)多少次事件。
這有點(diǎn)像公交車(chē), 無(wú)論在站點(diǎn)等車(chē)的人多不多,公交車(chē)只會(huì)按時(shí)來(lái)一班,不會(huì)來(lái)一個(gè)人就來(lái)一輛公交車(chē)。
標(biāo)準(zhǔn)節(jié)流function throttle(fn, wait) { let timeout; return function () { if (!timeout) { timeout = setTimeout(() => { timeout = null; fn.apply(this, arguments) }, wait) } } }
用滾動(dòng)事件來(lái)描述節(jié)流,其實(shí)是一個(gè)非常典型的場(chǎng)景,比如需要用滾動(dòng)事件判斷是否加載更多等。
先觸發(fā)式節(jié)流和防抖函數(shù)類(lèi)似,以上的情況是先等待后觸發(fā),如果我們想讓事件先觸發(fā)后等待,該如何處理呢?網(wǎng)上大部分文章都告訴你用時(shí)間戳的方式去實(shí)現(xiàn),其實(shí)只要像防抖一樣稍作修改即可實(shí)現(xiàn)。
function throttle(fn, wait) { let timeout; return function () { if (!timeout) { fn.apply(this, arguments) timeout = setTimeout(() => { timeout = null; }, wait) } } }
這樣,我們就會(huì)發(fā)現(xiàn)第一次觸發(fā)函數(shù)就會(huì)立即生效。
總結(jié)關(guān)于防抖與節(jié)流,lodash、underscore等工具庫(kù)都有完善的實(shí)現(xiàn)可以直接用,本沒(méi)有必要造輪子。本文的目的僅僅是為了將其主要思想和實(shí)現(xiàn)思路展現(xiàn)出來(lái)。更重要的,知道防抖和節(jié)流的本質(zhì)后,就知道在何時(shí)使用防抖或者節(jié)流,何時(shí)先觸發(fā)或后觸發(fā)。無(wú)論需求如何改變,都可以靈活的運(yùn)用。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/104789.html
摘要:函數(shù)防抖和節(jié)流,都是控制事件觸發(fā)頻率的方法。封裝一個(gè)函數(shù),讓持續(xù)觸發(fā)的事件監(jiān)聽(tīng)是我們封裝的這個(gè)函數(shù),將目標(biāo)函數(shù)作為回調(diào)傳進(jìn)去,等待一段時(shí)間過(guò)后執(zhí)行目標(biāo)函數(shù)第二點(diǎn)實(shí)現(xiàn)了,再看第一點(diǎn)持續(xù)觸發(fā)不執(zhí)行。 曾經(jīng)面試時(shí)候被問(wèn)到過(guò)這個(gè),年少的我一臉無(wú)知。。。 后來(lái)工作中遇到了一個(gè)場(chǎng)景:輸入名稱(chēng)的同時(shí)去服務(wù)器校驗(yàn)名稱(chēng)是否重復(fù),但發(fā)現(xiàn)之前的代碼竟然都沒(méi)做限制,輸入一次發(fā)一次請(qǐng)求。簡(jiǎn)直忍不了,就在項(xiàng)目的u...
摘要:關(guān)于防抖與節(jié)流的應(yīng)用和解釋自行查找資料。修改如果有定時(shí)器就清除如果時(shí)間滿足就讓他不滿足總之除了第一次就只讓其中一個(gè)執(zhí)行一開(kāi)始執(zhí)行一次時(shí)間戳,最后停止在執(zhí)行一次。 這一篇文章我想寫(xiě)一下防抖與節(jié)流,因?yàn)槲易约翰皇呛芾斫舛艺f(shuō)實(shí)話,以前知道,但是老忘,雖然概念還有一些簡(jiǎn)單的寫(xiě)法會(huì),但還是缺乏練習(xí)和深刻的理解。 showImg(https://segmentfault.com/img/remo...
摘要:若時(shí)間差大于間隔時(shí)間,則立刻執(zhí)行一次函數(shù)。不同點(diǎn)函數(shù)防抖,在一段連續(xù)操作結(jié)束后,處理回調(diào),利用和實(shí)現(xiàn)。函數(shù)防抖關(guān)注一定時(shí)間連續(xù)觸發(fā)的事件只在最后執(zhí)行一次,而函數(shù)節(jié)流側(cè)重于一段時(shí)間內(nèi)只執(zhí)行一次。 原博客地址,歡迎star 函數(shù)防抖和節(jié)流 函數(shù)防抖和函數(shù)節(jié)流:優(yōu)化高頻率執(zhí)行js代碼的一種手段,js中的一些事件如瀏覽器的resize、scroll,鼠標(biāo)的mousemove、mouseover...
摘要:對(duì)象是無(wú)法通過(guò)這種方式深拷貝。這就是函數(shù)防抖和節(jié)流要做的事情。函數(shù)防抖當(dāng)觸發(fā)頻率過(guò)高時(shí)函數(shù)基本停止執(zhí)行而函數(shù)節(jié)流則是按照一定的頻率執(zhí)行事件。 對(duì)象的深淺拷貝 對(duì)象的深拷貝與淺拷貝的區(qū)別: 淺拷貝:僅僅復(fù)制對(duì)象的引用, 而不是對(duì)象本身。 深拷貝:把復(fù)制的對(duì)象所引用的全部對(duì)象都復(fù)制一遍 淺拷貝的實(shí)現(xiàn): var obj = { age : 18, person : { ...
摘要:文章來(lái)源詳談防抖和節(jié)流輕松理解函數(shù)節(jié)流和函數(shù)防抖函數(shù)防抖和節(jié)流好啦,今天的小菊花課堂之的防抖與節(jié)流的內(nèi)容就告一段落啦,感各位能耐心看到這里。 前言 陸游有一首《冬夜讀書(shū)示子聿》——古人學(xué)問(wèn)無(wú)遺力,少壯工夫老始成。紙上得來(lái)終覺(jué)淺,絕知此事要躬行。,其中的意思想必大家都能明白,在學(xué)習(xí)或工作中,不斷的印證著這首詩(shī)的內(nèi)涵。所以,又有了此篇小菊花文章。 詳解 在前端開(kāi)發(fā)中,我們經(jīng)常會(huì)碰到一些會(huì)持...
閱讀 2403·2021-09-22 16:01
閱讀 3167·2021-09-22 15:41
閱讀 1182·2021-08-30 09:48
閱讀 501·2019-08-30 15:52
閱讀 3337·2019-08-30 13:57
閱讀 1725·2019-08-30 13:55
閱讀 3676·2019-08-30 11:25
閱讀 771·2019-08-29 17:25